背景
自己做了一点点的小尝试:基于前馈神经网络 LSTM 的个体出行目的地预测模型,基于个体历史出行数据,模型可以实现出行目的地的实时动态预测功能。
模型其实具有实际应用功能,为了对其应用场景进行探索,拟开发一个全栈的项目,在Web客户端实现用户出行的动态预测效果,同时能够提供数据可视分析等功能。
项目地址
可视化效果
Leftlet底图模块构建
需要安装的依赖库与样式查看Vue + Express + MySQL驾驶行为分析全栈项目(四): Leftlet组件与图层加载功能。
在 src/components/common 文件夹下添加 LeftletMap.vue文件,作为Leftlet地图的基础模块。
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
|
<template> <div class="map"> </div> </template>
<script>
export default { name: 'LeftletMap', data: function () { return { L: null, map: null, map_config: this.store.state.map_config }; }, methods: { initMap () { this.L = L; let map = L.map(this.$el, { center: this.map_config.center, zoom: this.map_config.zoom }); this.map = map; let baseLayer = L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?' + 'access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', { id: this.store.state.layerItems['box_d'], minZoom: 3 }); map.addLayer(baseLayer); } }, mounted () { this.initMap(); } }; </script>
<style scoped> .map { width: 100%; height: calc(88vh); position: relative; } </style>
|
其中 this.state 是用Vuex插件定义的全局状态变量,其本身是 src/store/index.js文件中定义的一个对象,在其中我们定义了各种地图的配置选项。具体内容可查看Vue + Express + MySQL驾驶行为分析全栈项目(四): Leftlet组件与图层加载功能。
热力图实现
首先安装leftlet热力图插件 leaflet-heatmap。
1
| npm i leaflet-heatmap --save
|
然后在src/views/ 文件夹下创建 ODpoint.vue 文件,该组件是对轨迹的O-D(Origin-Destination)点进行热力图分析。
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
| <template> <div> <Form ref="formInline" inline> <FormItem> 测试用户: <Select v-model="user" clearable style="width:70px"> <Option value="user1">User1</Option> <Option value="user2">User2</Option> <Option value="user3">User3</Option> <Option value="user4">User4</Option> </Select> </FormItem> <FormItem><b>出发时间:</b></FormItem> <FormItem> <DatePicker v-model="time_range" :start-date="new Date('2018-01-01 00:00:00')" type="datetimerange" style="width: 300px"></DatePicker> </FormItem> <FormItem> <CheckboxGroup v-model="ODSelectoin"> <Checkbox label="origin"></Checkbox> <Checkbox label="destination"></Checkbox> </CheckboxGroup> </FormItem> <FormItem> <Button type="primary" @click="show">展示</Button> </FormItem> </Form> <Map style="height: calc(78vh);" ref="leftletMap"></Map> </div> </template>
|
然后定义展示的逻辑js代码。一些问题可以参考文章:https://blog.frytea.com/archives/41/。
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
| import Map from '@/components/commom/LeftletMap'; import HeatmapOverlay from 'heatmap.js/plugins/leaflet-heatmap'; import {post, get} from '@/utils/myAjax'; import {points_factory} from '@/utils/traj-handler'
export default { name: 'od', data () { return { user: 'user1', time_range: ['2018-01-01 00:00:00', '2018-01-31:00:00:00'], ODSelectoin: ['origin'], heatmapLayer: null, cfg: { 'radius': 0.005, 'maxOpacity': 0.8, 'scaleRadius': true, 'useLocalExtrema': true, latField: 'lat', lngField: 'lng', valueField: 'eff' } }; }, mounted () { this.initHeatMap(); }, components: { Map }, methods: { show () { if (this.ODSelectoin.length === 0 || this.user === undefined) { this.$Message.info('请配置参数'); return null; } if (this.$isOnServer) { post('searchByRow', { rowName: ['origin', 'destination', 'norm_dict', 'o_eff', 'd_eff'], time: this.time_range, tableName: this.user }).then(data => { if (data.length > 0) { let res = points_factory(data, this.ODSelectoin); this.heatmapLayer.setData(res.data); this.$refs.leftletMap.map.setView(res.center, 10); } else { this.$Message.info('空数据'); } }); } else { get('../static/data/' + this.user + '.json').then(data => { if (data.RECORDS.length > 0) { let basket = []; let record = data.RECORDS; for (let item of record) { let tmp_date = new Date(item['time']); if (tmp_date >= this.time_range[0] && tmp_date <= this.time_range[1]) { basket.push(item); } } let res = points_factory(basket, this.ODSelectoin); this.heatmapLayer.setData(res.data); this.$refs.leftletMap.map.setView(res.center, 10); } else { this.$Message.info('空数据'); } }); } }, initHeatMap () { this.heatmapLayer = new HeatmapOverlay(this.cfg); this.heatmapLayer.addTo(this.$refs.leftletMap.map); L.control.scale({ maxWidth: 200, metric: true, imperial: false }).addTo(this.$refs.leftletMap.map); } } } ;
|
最后,预览效果:http://geoai.sunyunzeng.com/#/od