纽约州交通事故数据可视化
一、项目需求
数据:
https://data.cityofnewyork.us/api/views/h9gi-nx95/rows.csv?accessType=DOWNLOAD
功能:
- 在地图上显示出事故发生的地点
- 显示当前展示数据的统计图表
- 可以按时间、区域过滤
- 可以在地图指定任意点按地理半径过滤数据。例如:10公里内、50公里内
- 展示出导致事故发生因素
- 展示出事故发生因素之间的关系,给出出行建议
二、项目分析
题目要求将交通事故数据在地图上展示出来。首先,交通事故的数据格式是csv文件,需要在后端把csv格式的数据读取出来放在数据库中,然后根据前端发送的请求进行过滤处理后响应给前端,前端再调用地图接口将接收到的数据显示在地图上。所以,该项目涉及前后端全栈开发。
三、技术选型
首先,地图我想到的是选用百度地图,因为百度地图是国内的,申请开发者密钥比较方便,而google地图则需要翻墙;前端框架我选用的是react,使用其他框架也可以,看个人喜好;后端框架我选用的是express,因为不会其他的,哈哈;数据库选用mongodb,因为mongodb入门非常简单,很容易上手使用。
四、项目搭建
1、前端部分
前端用的是react框架,直接使用react脚手架create-react-app快速构建前端文件目录,也就是在终端执行create-react-app react-baidumap,react-baidumap就是我的前端部分的项目文件名,然后cd react-baidumap 进入项目文件,接着执行npm run eject(为了查看配置)和npm start就可以看到项目文件下自动创建的目录,打开localhost:3000可以看到react的官方图标。这部分的内容可以参考react官方教程:https://react.docschina.org/docs/create-a-new-react-app.html#create-react-app我也是照着官方教程来的。至此,前端的项目框架就搭建好了,如下图所示。

接着我们打开public文件夹,找到index.html文件,我们要使用百度地图接口,就需要在这里使用script标签引入资源,以下为index.html文件的内容:
<!DOCTYPE html>
<title>Vehicle Collisions</title>

然后就是在src文件夹下面的index.js文件里写代码了,这里注意要将BMap设置为全局变量来使用,不然会报错。具体如何使用百度地图可以参考百度地图官方文档上的Demohttp://lbsyun.baidu.com/jsdemo.htm#canvaslayer。如下所示,index.js文件的代码我写的注释已经很清楚了,这里不做过多解释了。
import React from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
import './index.css';
class BaiduMap extends React.Component {
componentDidMount() {
var BMap = window.BMap; //将BMap设置为全局变量
var map = new BMap.Map("container"); //创建map实例
var point = new BMap.Point(-73.8648270000,40.8447820000); //初始化地图,设置纽约为地图中心
map.centerAndZoom(point, 15); //设置地图显示级别为15
map.addControl(new BMap.MapTypeControl()); //添加地图类型控件
map.enableScrollWheelZoom(true); //开启鼠标滚轮缩放
// 编写自定义函数,创建标注,展示事故发生的地点和原因
function addMarker(point,string1,string2){
//给事故发生点添加标记
var marker = new BMap.Marker(point);
map.addOverlay(marker);
//展示事故发生原因
var label = new BMap.Label(string1,{offset:new BMap.Size(20,-10)});
marker.setLabel(label);
//点击展示展示事故发生因素之间的关系
marker.addEventListener("click",getAttr);
function getAttr(){
alert(string2);
}
}
//获取后端数据
axios.get('/getUserInfo').then(res => {
// var lng = res.data.result[0].LONGITUDE;
// var lat = res.data.result[0].LATITUDE;
// console.log(res.data.result[0].LONGITUDE);
// console.log(res.data.result[0].LATITUDE);
// var point1 = new BMap.Point(lng, lat);
// addMarker(point1);
res = res.data.result;
// console.log(res);
for( var i = 0, len = res.length; i < len; i++){
// console.log(res[i].LONGITUDE+'-----'+res[i].LATITUDE);
var point1 = new BMap.Point(res[i].LONGITUDE, res[i].LATITUDE);
addMarker(point1, res[i]['CONTRIBUTING FACTOR VEHICLE 1'], res[i]['CONTRIBUTING FACTOR VEHICLE 2']);
}
});
}
render() {
return (
<div
id='container'
style={{
width: '100vw',
height: '100vh'
}}>
</div>
)
}
}
ReactDOM.render(
<BaiduMap />,
document.getElementById('root')
)
2、后端部分
后端使用nodejs的express框架,需要在项目中安装express和mongodb,项目目录的构建其实很简单,这里还不需要路由和构建数据模型,因为不需要请求多个路径,而且数据是现成的,所以只要有个app.js入口文件,在这里面创建一个express应用,读取csv文件导入数据库,再连接数据库查找数据、响应请求就可以了。最开始我本来是打算前端和后端写在一个项目目录下,但是中途遇到了一些问题,当时自己对前后端的概念也是模糊不清,还尝试过在前端读取csv文件,最后也是以失败告终,后来请教他人之后,才把前后端的文件分开了,以下是我的后端项目目录:

其实这里主要就是app.js这个文件的编写,内容如下:
var express = require('express');
const router = express.Router();
var app = express();
var MongoClient = require('mongodb').MongoClient;
var url = 'mongodb://localhost:27017/mydata';
// 获取用户信息
router.get('/getUserInfo', function(req, res) {
MongoClient.connect(url, { useNewUrlParser: true },function(err,client){
if(err){
throw err;
// eslint-disable-next-line no-unreachable
console.log("数据库连接失败");
return;
}
console.log("数据库连接成功");
var db = client.db("mydata")
db.collection("userdata").find({},{"LOCATION": 1, "_id": 0}).limit(10).toArray(function(err,result){
if(err) throw err;
// console.log(result);
res.status(200).json({
result
});
client.close();
})
})
});
app.use('/', router);
app.all('/', function(req, res, next){
res.send("node启动成功");
next();
});
app.listen(3003, () => {
console.log('node服务器监听3003端口成功');
})
需要注意的是,mydata数据库是我事先已经建立好的,并且已经把交通事故的csv文件数据导入之后的。关于csv文件如何导入mongodb数据库就是一两行数据库指令,可以自行百度。另外,前后端交互的方式我用的是axios,node服务器运行在3003端口,前端运行在3000端口,所以记得在前端项目文件夹下的package.json文件中,添加这一行代码:"proxy": "http://localhost:3003",注意!这行代码必须添加到最后,至于为什么,我也不太清楚,哈哈。这样,前端就可以通过axios发送请求,后端收到请求后返回响应数据,前端拿到响应数据就可以展示给用户看了。
3、运行结果

五、项目总结
一个小小的交通事故数据可视化页面的制作,不仅仅有前端的工作,还有后端数据库的操作,以及前后端的交互联调,麻雀虽小,五脏俱全。通过这个小小的练手项目让我对前后端的工作有了一定理解,对前后端如何交互也有了认识。另外,其实这个项目我实现的功能很简陋,也就是只实现了最简单的展示功能,即在地图上展示了事故地点和事故原因以及点击事故地点显示事故分析,而查找、过滤、统计都没做。真正要做可视化,后续还要通过Echars工具来呈现更多的内容,后面有时间再继续完善这个项目吧。