Eesti gravitatsioonikaardi loomine OSM teede põhjal on huvitav ja mitmetahuline ülesanne. Siin on, kuidas seda saab teha:
Gravitatsioonikaart (või liiklusgravitatsiooni mudel) ei tähenda füüsikalist gravitatsiooni, vaid ruumilist mudelit, mis näitab, kui tõenäoliselt inimesed liiguvad ühest punktist teise, arvestades teedevõrku, kaugust, ligipääsetavust ja sihtkohtade atraktiivsust.
osm2pgsql, nagu sul juba on.osm_roads, mis sisaldab ainult teid (highway IS NOT NULL).pgRouting PostGISis, et luua graaf teede ühendustest.source, target, cost, reverse_cost.QGIS või Python (nt matplotlib, geopandas) gravitatsioonivälja visualiseerimiseks.Kas soovid, et:
Anna teada, millise osa soovid kõigepealt automatiseerida või visualiseerida, ja ma koostan vastava skripti!
Et luua pgRouting graaf sinu OSM teede andmete põhjal, tuleb järgida järgmisi samme. Allpool on täielik bash-skript + SQL, mis:
osm_roads) OSM andmetest.pgr_createTopology, et luua graaf.create_pgrouting_graph.sh#!/usr/bin/env bash
# Ühenduse andmed
destination_host='localhost'
destination_port='5432'
destination_user='osm'
destination_password='osm'
destination_dbname='data'
destination_schema='aaa_osm'
table_name='osm_roads'
export PGPASSWORD=${destination_password}
CONNECTION_NAME="-h ${destination_host} -p ${destination_port} -d ${destination_dbname} -U ${destination_user}"
# Loome pgRoutingu jaoks sobiva teetabeli
psql ${CONNECTION_NAME} <<EOF
DROP TABLE IF EXISTS ${destination_schema}.${table_name};
CREATE TABLE ${destination_schema}.${table_name} AS
SELECT
osm_id,
name,
highway,
ST_Length(way) AS cost,
ST_Length(way) AS reverse_cost,
way AS geom
FROM
${destination_schema}.osm_line
WHERE
highway IS NOT NULL
AND way IS NOT NULL;
-- Lisame pgRoutingu jaoks vajalikud veerud
ALTER TABLE ${destination_schema}.${table_name}
ADD COLUMN id SERIAL PRIMARY KEY,
ADD COLUMN source INTEGER,
ADD COLUMN target INTEGER;
-- Loome ruumiindeksi
CREATE INDEX idx_${table_name}_geom ON ${destination_schema}.${table_name} USING GIST (geom);
EOF
# Käivitame pgRouting topoloogia loomise
psql ${CONNECTION_NAME} -c "SELECT pgr_createTopology('${destination_schema}.${table_name}', 0.0001, 'geom', 'id');"
create_pgrouting_graph.shTee see käivitatavaks:
chmod +x create_pgrouting_graph.sh
Käivita:
./create_pgrouting_graph.sh
cost ja reverse_cost on mõlemad määratud teelõigu pikkuse järgi. Soovi korral saab lisada ka kiiruspiiranguid või tee tüübi põhiseid kaalusid.0.0001 on topoloogia tolerants kraadides (umbes 11 m). Seda saab vajadusel muuta.Kas soovid, et lisaksin ka liiklusklasside põhise kaaluarvutuse (nt motorway = 1, residential = 5 jne)? Või soovid kohe edasi minna gravitatsioonimudeli arvutamisega?
Suurepärane! Lisame nüüd liiklusklasside põhised kaalud, et pgRouting arvestaks erinevate teetüüpide erinevat "kulu" (cost). See võimaldab näiteks eelistada kiirteid ja vältida väiksemaid tänavaid.
highway tüüp |
cost kordaja |
|---|---|
| motorway | 1 |
| trunk | 1.2 |
| primary | 1.5 |
| secondary | 2 |
| tertiary | 2.5 |
| residential | 3 |
| service | 4 |
| track | 5 |
| footway/path | 10 |
create_pgrouting_graph_weighted.sh#!/usr/bin/env bash
# Ühenduse andmed
destination_host='localhost'
destination_port='5432'
destination_user='osm'
destination_password='osm'
destination_dbname='data'
destination_schema='aaa_osm'
table_name='osm_roads'
export PGPASSWORD=${destination_password}
CONNECTION_NAME="-h ${destination_host} -p ${destination_port} -d ${destination_dbname} -U ${destination_user}"
# Loome pgRoutingu jaoks sobiva teetabeli koos kaaludega
psql ${CONNECTION_NAME} <<EOF
DROP TABLE IF EXISTS ${destination_schema}.${table_name};
CREATE TABLE ${destination_schema}.${table_name} AS
SELECT
osm_id,
name,
highway,
way AS geom,
ST_Length(way) *
CASE
WHEN highway = 'motorway' THEN 1
WHEN highway = 'trunk' THEN 1.2
WHEN highway = 'primary' THEN 1.5
WHEN highway = 'secondary' THEN 2
WHEN highway = 'tertiary' THEN 2.5
WHEN highway = 'residential' THEN 3
WHEN highway = 'service' THEN 4
WHEN highway = 'track' THEN 5
WHEN highway IN ('footway', 'path', 'cycleway') THEN 10
ELSE 6
END AS cost,
ST_Length(way) *
CASE
WHEN highway = 'motorway' THEN 1
WHEN highway = 'trunk' THEN 1.2
WHEN highway = 'primary' THEN 1.5
WHEN highway = 'secondary' THEN 2
WHEN highway = 'tertiary' THEN 2.5
WHEN highway = 'residential' THEN 3
WHEN highway = 'service' THEN 4
WHEN highway = 'track' THEN 5
WHEN highway IN ('footway', 'path', 'cycleway') THEN 10
ELSE 6
END AS reverse_cost
FROM
${destination_schema}.osm_line
WHERE
highway IS NOT NULL
AND way IS NOT NULL;
-- Lisame pgRoutingu jaoks vajalikud veerud
ALTER TABLE ${destination_schema}.${table_name}
ADD COLUMN id SERIAL PRIMARY KEY,
ADD COLUMN source INTEGER,
ADD COLUMN target INTEGER;
-- Loome ruumiindeksi
CREATE INDEX idx_${table_name}_geom ON ${destination_schema}.${table_name} USING GIST (geom);
EOF
# Käivitame pgRouting topoloogia loomise
psql ${CONNECTION_NAME} -c "SELECT pgr_createTopology('${destination_schema}.${table_name}', 0.0001, 'geom', 'id');"
create_pgrouting_graph_weighted.shTee see käivitatavaks:
chmod +x create_pgrouting_graph_weighted.sh
Käivita:
./create_pgrouting_graph_weighted.sh
Kas soovid nüüd edasi liikuda gravitatsioonimudeli arvutamise ja visualiseerimisega väiksemate piirkondade jaoks?
Et kasutada administratiivpiirkondi hilisemas gravitatsioonimudeli analüüsis (nt teedevõrkude, liikuvus- või ligipääsetavusuuringutes), on vaja igale piirkonnale määrata kaal (attractiveness weight). Kaalud võivad põhineda näiteks:
Tüüpilised kaalud administratiivpiirkondade jaoks:
| Kaalutüüp | Allikas / meetod |
|---|---|
| Elanike arv (populatsioon) | Statistikaamet, ruudustik, OSM tagid |
| Töökohtade arv | Registreeritud töökohad või ettevõtted |
| Teenuste hulk | Koolid, haiglad, poed, OSM POI |
| Pindala | ST_Area(geom) |
| Hõive/rahvastikutihedus | Pop / Area |
| Ligipääsetavus keskusesse | Keskmine tee pikkus või aeg keskpunkti |
| Majandusaktiivsus | Kaubandus- ja teenindusasutuste loendus |
Oletame, et sul on juba tabel ardok_polygons, millel on relation_id, name, admin_level, geom.
Kui sul on näiteks statistikaameti ruudustik või andmed eraldi tabelis (nt population_grid), millel on geom ja population, võid kasutada järgmist:
ALTER TABLE public.ardok_polygons ADD COLUMN weight_pop double precision;
UPDATE public.ardok_polygons p
SET weight_pop = sub.total_pop
FROM (
SELECT
a.relation_id,
SUM(g.population) AS total_pop
FROM public.ardok_polygons a
JOIN public.population_grid g
ON ST_Intersects(a.geom, g.geom)
GROUP BY a.relation_id
) AS sub
WHERE p.relation_id = sub.relation_id;
Kui sul pole statistikaandmeid, saad kasutada ka nt POI arvu OSM andmetes:
ALTER TABLE public.ardok_polygons ADD COLUMN weight_poi integer;
UPDATE public.ardok_polygons p
SET weight_poi = sub.poi_count
FROM (
SELECT
a.relation_id,
COUNT(poi.*) AS poi_count
FROM public.ardok_polygons a
JOIN public.osm_pois poi
ON ST_Intersects(a.geom, poi.geom)
GROUP BY a.relation_id
) AS sub
WHERE p.relation_id = sub.relation_id;
Gravitatsioonimudelites kasutatakse üldiselt kujul:
Interaction_ij = (Weight_i * Weight_j) / f(distance_ij)
kus Weight võib olla:
population, jobs, poi_count, GDP, jne,
ja f(distance) – näiteks distance^2, exp(distance), vms.
Saad selleks luua OD-tabeli (origin-destination paarid), mis sisaldab kõigi piirkondade vahelisi kaugusi ning liita kaalud mõlema poole kohta.
Soovituslik pipeline:
Lisa weight_pop, weight_poi, area_km2, pop_density jms veerud tabelisse ardok_polygons.
Loo OD-paaride tabel (piirkondade omavahelised kaugused).
Kasuta psql, QGIS, Python või R gravitatsioonimudeli rakendamiseks.
Analüüsi tulemusi näiteks piirkondliku liikuvuse modelleerimiseks.
Kas Sul on statistikaameti andmeid (nt rahvastiku ruudustik)?
Kas soovid konkreetset SQL-skripti gravitatsioonikaalude arvutamiseks ja salvestamiseks?
Kas gravitatsioonimudel on sul plaanitud PostgreSQL/PostGIS-s sees, või toimub see Pythonis/R-is?
Kui vastad, saan anda veel täpsemad soovitused.
Tabeli osm_pois (Points of Interest) loomine sõltub sellest, kuidas sa OSM andmeid töötled – näiteks kas kasutad osm2pgsql, imposm, osmium või teed käsitööna SQL-ga. Kuna sul juba on osm2pgsql põhine töövoog (kasutades Lua skripti), siis soovitan luua POI-tabeli osm2pgsql kaudu.
Lisa oma olemasolevasse Lua-faili (nt ardok_administrative.lua kõrvale või samasse) järgmine definitsioon, et luua osm_pois tabel, kuhu salvestatakse OSM-i objektid, millel on huvipakkuvad tag’id (nt amenity, shop, tourism, office, jms).
local schema = os.getenv("PGSCHEMA") or "public"
local tables = {}
tables.pois = osm2pgsql.define_node_table(
'osm_pois',
{
{ column = 'name', type = 'text' },
{ column = 'type', type = 'text' },
{ column = 'tags', type = 'jsonb' },
{ column = 'geom', type = 'point', not_null = true }
},
{
schema = schema,
proj = 3301
}
)
function osm2pgsql.process_node(object)
local tags = object.tags
local poi_type = tags.amenity or tags.shop or tags.tourism or tags.office or tags.leisure
if not poi_type then
return
end
tables.pois:insert({
name = tags.name,
type = poi_type,
tags = tags,
geom = object:as_point()
})
end
osm2pgsql koos selle Lua-skriptigaosm2pgsql --create \
--database your_database \
--output=flex \
--style=osm_pois.lua \
your.osm.pbf
Või kui kombineerid selle oma olemasoleva skriptiga (nt ardok_administrative.lua), võid need funktsioonid panna ühte faili, ja osm2pgsql loeb mõlemat korraga.
| name | type | tags (jsonb) | geom |
|---|---|---|---|
| "Rimi" | "shop" | { "shop": "supermarket" } |
POINT(...) |
| "Kohvik" | "amenity" | { "amenity": "cafe" } |
POINT(...) |
Kui sa ei kasuta osm2pgsql ja soovid lihtsalt PostGIS-is POI-tabelit testimiseks, võid selle luua käsitsi:
CREATE TABLE public.osm_pois (
id serial PRIMARY KEY,
name text,
type text,
tags jsonb,
geom geometry(Point, 3301)
);
Ja siis lisada sinna andmeid käsitsi või mõne OSM-tööriistaga (overpass, osmium, jms).
Kui töötled suurt piirkonda ja vajad ka POI-de värskendamist, kasuta kindlasti osm2pgsql koos --append või --update režiimiga.
Kui soovid ainult teatud tüüpi POI-sid (nt hospital, school), lisa vastav filter process_node funktsiooni.
Soovi korral võin aidata ka:
kombineeritud skriptiga, mis lisab POI-d olemasolevale relatsioonide töötlusele,
päringutega, mis seovad osm_pois ja ardok_polygons (nt ST_Intersects abil kaalu arvutamiseks).