forked from ChelseaKR/nearmiss
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfetch_simra.py
More file actions
84 lines (68 loc) · 3.17 KB
/
Copy pathfetch_simra.py
File metadata and controls
84 lines (68 loc) · 3.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#!/usr/bin/env python3
# SPDX-License-Identifier: Apache-2.0
"""Convert real SimRa bicycle near-miss data into the nearmiss *intake* format.
SimRa (https://github.com/simra-project/dataset, TU Berlin) is a crowdsourced,
openly-published dataset of **bicycle near-crashes** with GPS — the closest
real-world analogue to nearmiss's own input, and unusual in that the same source
also carries the *ride* GPS traces, which are a natural exposure denominator.
Each SimRa ride file has an incidents section (one annotated near-miss per row:
``lat,lon,ts,…,incident,…,scary,…``) then a divider then the ride GPS trace. This
tool reads a directory of such files and emits reports conforming to
``schema/report.schema.json`` — ready for ``nearmiss intake``. It does not touch
exposure or the street network (see docs/REAL-DATA.md); those are separate inputs,
though SimRa's ride traces can supply both.
This is a thin CLI over the ``SimRaAdapter`` in ``nearmiss.adapters.simra`` (the
second ``SourceAdapter`` implementation, EXP-04 — this tool was previously an
orphaned, unmerged branch; it is now a manifest + adapter module like BikeMaps).
The incident-code crosswalk lives as declarative data in
``src/nearmiss/adapters/crosswalks/simra.toml``.
Usage:
python tools/fetch_simra.py --dir path/to/SimRa/Berlin_2023_03 --out reports.json
python tools/fetch_simra.py --dir path/to/SimRa --city berlin --out reports.json
"""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
from nearmiss.adapters.simra import CITY_BBOX, collect, in_bbox, map_incident, parse_incidents
__all__ = [
"CITY_BBOX",
"collect",
"in_bbox",
"main",
"map_incident",
"parse_args",
"parse_incidents",
]
def parse_args(argv: list[str]) -> argparse.Namespace:
p = argparse.ArgumentParser(
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
)
p.add_argument("--dir", required=True, help="A SimRa region folder (or a parent of folders).")
p.add_argument("--city", choices=sorted(CITY_BBOX), help="Restrict to a known city's bbox.")
p.add_argument("--bbox", help="Bounding box W,S,E,N in degrees (overrides --city).")
p.add_argument("--out", default="-", help="Output reports.json ('-' for stdout).")
return p.parse_args(argv)
def main(argv: list[str]) -> int:
args = parse_args(argv)
bbox: tuple[float, float, float, float] | None = None
if args.bbox:
parts = [float(x) for x in args.bbox.split(",")]
if len(parts) != 4:
print("error: --bbox must be W,S,E,N", file=sys.stderr)
return 2
bbox = (parts[0], parts[1], parts[2], parts[3])
elif args.city:
bbox = CITY_BBOX[args.city]
reports = collect(Path(args.dir), bbox)
text = json.dumps({"reports": reports}, ensure_ascii=False, indent=2)
if args.out == "-":
print(text)
else:
Path(args.out).write_text(text + "\n", encoding="utf-8")
where = "stdout" if args.out == "-" else args.out
print(f"fetch_simra: wrote {len(reports)} real near-miss reports to {where}", file=sys.stderr)
return 0
if __name__ == "__main__":
raise SystemExit(main(sys.argv[1:]))