Implement difference between urban and rural for events and road segments.
This commit is contained in:
parent
8728347695
commit
66dd84982c
25
api/migrations/versions/b22108ab2ffb_add_event_zone.py
Normal file
25
api/migrations/versions/b22108ab2ffb_add_event_zone.py
Normal 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")
|
|
@ -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}>"
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
},
|
||||
}
|
||||
)
|
||||
|
|
|
@ -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())),
|
||||
}
|
||||
|
|
|
@ -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)',
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
)}
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
|
|
|
@ -163,6 +163,7 @@ module.exports = function (webpackEnv) {
|
|||
'/config.json': apiUrl,
|
||||
'/api': apiUrl,
|
||||
'/login': apiUrl,
|
||||
'/tiles': apiUrl
|
||||
},
|
||||
},
|
||||
module: {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue