Implement difference between urban and rural for events and road segments.

This commit is contained in:
gluap 2022-05-02 22:00:17 +02:00
parent 8728347695
commit 66dd84982c
14 changed files with 104 additions and 15 deletions

View file

@ -0,0 +1,25 @@
"""add event zone
Revision ID: b22108ab2ffb
Revises: a9627f63fbed
Create Date: 2022-04-30 19:06:11.472579
"""
from alembic import op
import sqlalchemy as sa
from migrations.utils import dbtype
# revision identifiers, used by Alembic.
revision = 'b22108ab2ffb'
down_revision = 'a9627f63fbed'
branch_labels = None
depends_on = None
def upgrade():
op.add_column("overtaking_event", sa.Column("zone", dbtype("zone_type")), )
def downgrade():
op.drop_column("overtaking_event", "zone")

View file

@ -124,6 +124,7 @@ class OvertakingEvent(Base):
distance_stationary = Column(Float)
course = Column(Float)
speed = Column(Float)
zone = Column(ZoneType)
def __repr__(self):
return f"<OvertakingEvent {self.id}>"

View file

@ -27,7 +27,7 @@ from obs.face.filter import (
from obs.face.osm import DataSource, DatabaseTileSource, OverpassTileSource
from obs.api.db import OvertakingEvent, RoadUsage, Track, make_session
from obs.api.db import OvertakingEvent, RoadUsage, Track, make_session, ZoneType
from obs.api.app import app
log = logging.getLogger(__name__)
@ -293,6 +293,7 @@ async def import_overtaking_events(session, track, overtaking_events):
distance_stationary=m["distance_stationary"],
course=m["course"],
speed=m["speed"],
zone=m["OSM_zone"] if ('OSM_zone' in m and m['OSM_zone'] is not None) else "urban"
)
session.add_all(event_models.values())

View file

@ -77,6 +77,7 @@ async def export_events(req):
writer.field("direction", "N", decimal=0)
writer.field("course", "N", decimal=4)
writer.field("speed", "N", decimal=4)
writer.field("zone", "N", decimal=4)
async for event in events:
writer.point(event.longitude, event.latitude)
@ -87,6 +88,7 @@ async def export_events(req):
way_id=event.way_id,
course=event.course,
speed=event.speed,
zone=event.zone
# "time"=event.time,
)
@ -107,6 +109,7 @@ async def export_events(req):
"course": event.course,
"speed": event.speed,
"time": event.time,
"zone": event.zone
},
}
)

View file

@ -112,6 +112,7 @@ async def mapdetails_road(req):
"histogram": {
"bins": [None if math.isinf(b) else b for b in bins.tolist()],
"counts": hist.tolist(),
"zone": road.zone
},
"values": list(map(rounder, arr.tolist())),
}

View file

@ -47,24 +47,64 @@ export function colorByCount(attribute = 'event_count', maxCount, colormap = vir
return colormapToScale(colormap, ['case', ['to-boolean', ['get', attribute]], ['get', attribute], 0], 0, maxCount)
}
export function colorByDistance(attribute = 'distance_overtaker_mean', fallback = '#ABC') {
var steps = {'rural': [1.6,1.8,2.0,2.2],
'urban': [1.1,1.3,1.5,1.7]}
export function borderByZone() {
return ["match", ['get', 'zone'],
"rural", "brown",
"urban", "olive",
"purple"
]
}
export function colorByDistance(attribute = 'distance_overtaker_mean', fallback = '#ABC', zone='urban') {
return [
'case',
['!', ['to-boolean', ['get', attribute]]],
fallback,
["match", ['get', 'zone'], "rural",
[
'step',
['get', attribute],
'rgba(150, 0, 0, 1)',
1.1,
steps['rural'][0],
'rgba(255, 0, 0, 1)',
1.3,
steps['rural'][1],
'rgba(255, 220, 0, 1)',
1.5,
steps['rural'][2],
'rgba(67, 200, 0, 1)',
1.7,
steps['rural'][3],
'rgba(67, 150, 0, 1)',
], "urban",
[
'step',
['get', attribute],
'rgba(150, 0, 0, 1)',
steps['urban'][0],
'rgba(255, 0, 0, 1)',
steps['urban'][1],
'rgba(255, 220, 0, 1)',
steps['urban'][2],
'rgba(67, 200, 0, 1)',
steps['urban'][3],
'rgba(67, 150, 0, 1)',
],
[
'step',
['get', attribute],
'rgba(150, 0, 0, 1)',
steps['urban'][0],
'rgba(255, 0, 0, 1)',
steps['urban'][1],
'rgba(255, 220, 0, 1)',
steps['urban'][2],
'rgba(67, 200, 0, 1)',
steps['urban'][3],
'rgba(67, 150, 0, 1)',
]
]
]
}

View file

@ -98,7 +98,10 @@ function LayerSidebar({
) :
(
<List.Item>
<DiscreteColorMapLegend map={colorByDistance('distance_overtaker')[3].slice(2)} />
<span style={{color: "olive"}}>Urban</span>
<DiscreteColorMapLegend map={colorByDistance('distance_overtaker')[3][5].slice(2)} />
<span style={{color: "brown"}}>Rural</span>
<DiscreteColorMapLegend map={colorByDistance('distance_overtaker')[3][3].slice(2)} />
</List.Item>
)}
</>
@ -120,7 +123,10 @@ function LayerSidebar({
{showEvents && (
<>
<List.Item>
<DiscreteColorMapLegend map={colorByDistance('distance_overtaker')[3].slice(2)} />
<span style={{color: "olive"}}>Urban</span>
<DiscreteColorMapLegend map={colorByDistance('distance_overtaker')[3][5].slice(2)} />
<span style={{color: "brown"}}>Rural</span>
<DiscreteColorMapLegend map={colorByDistance('distance_overtaker')[3][3].slice(2)} />
</List.Item>
</>
)}

View file

@ -9,7 +9,7 @@ import {Chart} from 'components'
import {pairwise} from 'utils'
import api from 'api'
import {colorByDistance} from 'mapstyles'
import {colorByDistance, borderByZone} from 'mapstyles'
import styles from './styles.module.less'
@ -75,14 +75,15 @@ function RoadStatsTable({data}) {
)
}
function HistogramChart({bins, counts}) {
function HistogramChart({bins, counts, zone}) {
const diff = bins[1] - bins[0]
const colortype = zone=="rural" ? 3:5;
const data = _.zip(
bins.slice(0, bins.length - 1).map((v) => v + diff / 2),
counts
).map((value) => ({
value,
itemStyle: {color: selectFromColorMap(colorByDistance()[3].slice(2), value[0])},
itemStyle: {color: selectFromColorMap(colorByDistance()[3][colortype].slice(2), value[0]),},
}))
return (

View file

@ -6,7 +6,7 @@ import produce from 'immer'
import {Page, Map} from 'components'
import {useConfig} from 'config'
import {colorByDistance, colorByCount, reds} from 'mapstyles'
import {colorByDistance, colorByCount, borderByZone, reds} from 'mapstyles'
import {useMapConfig} from 'reducers/mapConfig'
import RoadInfo from './RoadInfo'
@ -67,6 +67,8 @@ const getEventsLayer = () => ({
paint: {
'circle-radius': ['interpolate', ['linear'], ['zoom'], 14, 3, 17, 8],
'circle-color': colorByDistance('distance_overtaker'),
'circle-stroke-color': borderByZone(),
'circle-stroke-width':['interpolate', ['linear'], ['zoom'], 14, 1, 17, 4],
},
minzoom: 11,
})

View file

@ -163,6 +163,7 @@ module.exports = function (webpackEnv) {
'/config.json': apiUrl,
'/api': apiUrl,
'/login': apiUrl,
'/tiles': apiUrl
},
},
module: {

View file

@ -1,5 +1,5 @@
CREATE OR REPLACE FUNCTION layer_obs_events(bbox geometry, zoom_level int)
RETURNS TABLE(event_id bigint, geometry geometry, distance_overtaker float, distance_stationary float, direction int, course float, speed float, way_id bigint) AS $$
RETURNS TABLE(event_id bigint, geometry geometry, distance_overtaker float, distance_stationary float, direction int, course float, speed float, zone zone_type, way_id bigint) AS $$
SELECT
id::bigint as event_id,
@ -9,6 +9,7 @@ RETURNS TABLE(event_id bigint, geometry geometry, distance_overtaker float, dist
(case when direction_reversed then -1 else 1 end)::int as direction,
course,
speed,
zone,
way_id::bigint as way_id
FROM overtaking_event
WHERE ST_Transform(overtaking_event.geometry, 3857) && bbox;

View file

@ -16,6 +16,8 @@ layer:
Direction of travel, as reported by GPS, in degree from North.
speed: |
Speed of travel, as reported by GPS, in meters per second (?).
zone: |
rural or urban
defaults:
srs: EPSG:3785
datasource:
@ -23,7 +25,7 @@ layer:
geometry_field: geometry
key_field: event_id
key_field_as_attribute: no
query: (SELECT event_id, geometry, distance_overtaker, distance_stationary, direction, course, speed, way_id FROM layer_obs_events(!bbox!, z(!scale_denominator!))) AS t
query: (SELECT event_id, geometry, distance_overtaker, distance_stationary, direction, course, speed, zone, way_id FROM layer_obs_events(!bbox!, z(!scale_denominator!))) AS t
schema:
- ./layer.sql

View file

@ -12,6 +12,7 @@ RETURNS TABLE(
overtaking_event_count int,
usage_count bigint,
direction int,
zone zone_type,
offset_direction int
) AS $$
@ -27,12 +28,13 @@ RETURNS TABLE(
(select count(id) from road_usage where road_usage.way_id = road.way_id and
(road.directionality != 0 or road_usage.direction_reversed = r.rev)) as usage_count,
r.dir as direction,
road.zone::zone_type as zone,
case when road.directionality = 0 then r.dir else 0 end as offset_direction
FROM road
LEFT JOIN (VALUES (-1, TRUE), (1, FALSE), (0, FALSE)) AS r(dir, rev) ON (abs(r.dir) != road.directionality)
FULL OUTER JOIN overtaking_event ON (road.way_id = overtaking_event.way_id and (road.directionality != 0 or overtaking_event.direction_reversed = r.rev))
-- WHERE road.name = 'Merzhauser Straße'
WHERE road.geometry && bbox
GROUP BY road.name, road.way_id, road.geometry, road.directionality, r.dir, r.rev;
GROUP BY road.name, road.way_id, road.geometry, road.directionality, r.dir, r.rev, road.zone;
$$ LANGUAGE SQL IMMUTABLE;

View file

@ -22,6 +22,8 @@ layer:
Contains -1 for events while going along the way backwards, 1 for
forwards. Each road is emitted twice, if it has data for both directions,
even if it is oneway.
zone: |
ural or urban
offset_direction: |
Factor for offset to shift the line to the driving side. One of -1, 0, 1.
defaults:
@ -44,6 +46,7 @@ layer:
overtaking_event_count,
usage_count,
direction,
zone,
offset_direction
FROM layer_obs_roads(!bbox!, z(!scale_denominator!))
) AS t