CartoWeave is a modern map label layout engine designed for research and rapid experimentation. The legacy "engine" and "orchestrators" modules have been retired in favour of a compute-only pipeline with pluggable passes and solvers. Lightweight visualization helpers remain for inspecting intermediate results.
This new structure makes it easy to prototype new label placement strategies without rebuilding common infrastructure.
- Pluggable force terms for point, line and area labels
- Example configurations for common layouts
- Multiple solvers: L-BFGS and semi-Newton
- Pass manager with scheduling, clipping and capture hooks
- Random scene generator for demos and tests
pip install cartoweave # once published
# or from source
pip install -e .The result contains coordinates for the last frame of each action only. The
frame_size=(W, H) argument is required and must match your scene coordinates.
from cartoweave import solve_layout
labels = [
{"label_id": 0, "WH": [80, 24], "anchor": {"kind": "point", "element_id": 0}},
]
elements = {"points": [{"element_id": 0, "xy": [100.0, 200.0]}]}
actions = [{"t": 0, "op": "activate", "label_ids": "all"}]
cfg = {
"compute": {"public": {"forces": {"anchor.spring": {"enable": True, "k_local": 1.0}}}},
}
res = solve_layout(labels, elements, actions, frame_size=(1280, 800), config_profile=cfg)
print(res.coords[-1]) # final coordinates after the actionRun python examples/minimal_solve.py for a small working demo. For running a
specific call from a payload JSON and opening the interactive viz, try:
python examples/run_payload_shot_viz.py --file cartoweave_payload_latest.json --shot 2 --frame 1280 800 --vizEach element (point, polyline or polygon) should provide an element_id so
that labels can reference it via their anchor field. Labels themselves use
label_id and actions reference labels via label_ids.
from cartoweave.data.api import (
build_solvepack_from_config,
load_solvepack_from_file,
)Canonical YAML snippet:
data:
source: random
path: ""
regen: false
frame: { width: 1280, height: 800 }
counts:
labels: 16
points: 6
lines: 4
areas: 2
random:
route_gen:
segment_len_scale: 0.06
inset_margin_scale: 0.05
min_vertex_spacing_scale: 0.03
area_gen:
inset_margin_scale: 0.06
min_edge_spacing_scale: 0.03
anchors:
policy: auto
modes:
line: projected
area: projected_edge
steps:
kind: sequential
steps: 16steps.kind="none"⇒ single stage (no actions).steps.kind="sequential":- if
steps == labels⇒ one label per step; - if
steps < labels⇒ firststeps-1add one label each; last stage activates all remaining.
- if
steps.kind="grouped": viagroup_sizesor explicitgroups.
python -m cartoweave solve --config examples/configs/compute_min.json --scene examples/scenes/scene_min.jsonexamples/minimal_solve.py– minimal example of solving a single frame
- We ship a conservative pass setup by default:
step_limitenabled (defaultmax_step_norm: 60) to cap per‑step motion.grad_clipenabled (defaultmax_norm: 1000.0) to tame extreme gradients.- You can raise
grad_clip.max_normor disable it if your first pass needs a stronger initial push; keepstep_limitto prevent overshoot.
appear_nudgegives newly activated labels a gentle initial displacement; you can raisestep_px(e.g. 4–8) for clearer “push‑off” in the first pass.area.crossuses a continuous gate with AABB pre‑clipping and short‑edge skipping for robust collision handling.
- Rectangle kernel:
ll.rect(anisotropic, respects W×H) - Disk/Ellipse kernel:
ll.diskll_disk_mode: max|min|avg|diag|ellipseellipseuses directional support radii of axis‑aligned ellipses for a more faithful interaction with wide/flat labels.
anchor.springacts on point/line anchors; area‑anchored labels are constrained byarea.*terms (area.embed,area.cross,area.softout).
cartoweave/compute– compute pipeline with forces, passes and solverscartoweave/data– random scene utilities and data APIcartoweave/viz– placeholders for visualisation toolstests– unit tests and integration tests
pytestCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0). You may copy and modify the code for non-commercial purposes, provided you give appropriate credit and distribute your contributions under the same license. See the LICENSE file for details.
CartoWeave 是一个现代化的地图标注布局引擎,适用于科研和快速原型开发。旧版的 engine/orchestrators 模块已被移除,现在的框架专注于 compute 管线和可插拔的 求解 passes,仍保留轻量级的可视化工具。
- 可插拔的力项,支持点、线、面三类标注;
- 预设的配置模板,便于快速开始;
- 多种求解器:L-BFGS、半牛顿法;
- PassManager 提供调度、裁剪和捕获等扩展点;
- 随机场景生成器,方便进行演示和测试。
pip install cartoweave # 正式发布后可直接安装
# 或者从源码安装
pip install -e .返回结果仅包含每个动作最终一步的坐标。
from cartoweave import solve_layout
labels = [
{"label_id": 0, "WH": [80, 24], "anchor": {"kind": "point", "element_id": 0}},
]
elements = {"points": [{"element_id": 0, "xy": [100.0, 200.0]}]}
actions = [{"t": 0, "op": "activate", "label_ids": "all"}]
cfg = {
"compute": {"public": {"forces": {"anchor.spring": {"enable": True, "k_local": 1.0}}}},
}
res = solve_layout(labels, elements, actions, frame_size=(1280, 800), config_profile=cfg)
print(res.coords[-1])运行 python examples/minimal_solve.py 可以看到一个最小示例;如果将
viz.show 设为 True,还能体验交互式查看器。
每个场景元素(点、线、面)需提供 element_id,标注使用 label_id,
动作通过 label_ids 指定作用的标注。
examples/minimal_solve.py– 拟合单帧的最小示例examples/solve_layout_api.py– 展示外部solve_layout接口处理点、线、面场景并包含多动作examples– 更多展示场景和步骤配置方式的脚本
- 默认包含以下保护:
step_limit启用(默认max_step_norm: 60)限制单步位移;grad_clip启用(默认max_norm: 1000.0)裁剪大梯度;- 若首帧需要更强的“推开”,可调大
grad_clip.max_norm或临时关闭,同时保留step_limit;也可调大appear_nudge.step_px(如 4–8)。
area.cross使用连续门函数 + AABB 预裁剪 + 短边跳过,更稳健。
- 矩形核:
ll.rect(各向异性,遵循宽高) - 圆/椭圆核:
ll.diskll_disk_mode: max|min|avg|diag|ellipseellipse使用轴对齐椭圆在方向上的支持函数,更适合“又宽又扁”的标签。
anchor.spring作用于点/线锚;面锚由area.*(area.embed、area.cross、area.softout)约束。
cartoweave/compute– 核心计算管线,包含力项、passes 和求解器;cartoweave/data– 随机场景与数据 API;cartoweave/viz– 计划中的可视化工具;tests– 单元测试与集成测试。
pytest本项目采用 Creative Commons 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)许可证。您可以在非商业目的下复制和修改代码,但必须标注 作者并以相同的协议共享您的贡献。详见 LICENSE 文件。