【2019数模国赛C题】js+BaiduMap API实现上海浦东机场出租车行车路径可视化
作为数学苦手,每次参加数模(虽然加上这次也就两次)都是抱着划水抱大腿的打算参加的……C题要求的是搜集某城市航班和该城市机场出租相关信息,航班信息倒简单,爬一下携程、飞常准之类的网站就行了。机场出租信息真是要了老命……按思路有两种,一种是查机场出租车秩序站的相关接口,在某乎上有看到有匿名网友爬到了郑州新郑机场出租车秩序站的一个网页,但找来找去没找着;第二种则是统计筛选某城市所有出租车的GPS路径,本来觉得这数据处理也太麻烦了,也找不到数据。在几乎打算直接编造数据的时候,在某乎上找到了一份2007年上海出租车的GPS数据,处理了一下也还好。做了个简单的可视化,虽然对论文估计没啥用,但还是挺有意思的,这里记录一下简单的js和相关接口的运用,萌新如我也可以轻松学会。
数据格式
一段示例数据:
2108,2007-02-20 00:01:06,121.438500,31.249000, 0, 45,0
2108,2007-02-20 00:02:07,121.438500,31.249000, 0, 45,0
2108,2007-02-20 00:03:08,121.438500,31.249000, 0, 45,0
2108,2007-02-20 00:04:09,121.438500,31.249000, 0, 45,0
编号 | 时间 | 经度 | 纬度 | 速度 | 偏移角度 | 载客状态 |
---|---|---|---|---|---|---|
2108 | 2007-02-20 00:01:06 | 121.438500 | 31.249000 | 0 | 45 | 0 |
实现过程
整个数据有4000多份,每一份都是一辆出租车一天约每隔一分钟产生的位置信息。因为其中不乏没有出动的、只在市区载客的出租车,我们需要筛选出经过上海浦东机场的数据,从百度地图上找出上海浦东机场的位置为[121.81509,31.157478],为了方便简单的定义经过该坐标半径3000m即视作经过浦东机场。
# -*- coding:utf-8 -*-
import os
from math import radians, cos, sin, asin, sqrt
import shutil#计算两点间距离-m
def geodistance(lng1,lat1,lng2,lat2):lng1, lat1, lng2, lat2 = map(radians, [lng1, lat1, lng2, lat2])dlon=lng2-lng1dlat=lat2-lat1a=sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2dis=2*asin(sqrt(a))*6371*1000return disdef all_path(dirname):result = []#所有的文件for maindir, subdir, file_name_list in os.walk(dirname):for filename in file_name_list:apath = os.path.join(maindir, filename)#合并成一个完整路径result.append(apath)return resultif __name__ == '__main__':dis = [121.81509,31.157478]path = r'E:\杂图作品\20190912数学建模\数据(打开前请看备注)'to_path = r'E:\杂图作品\20190912数学建模\经过浦东机场的数据'txts = all_path(path)count = 0;for i in txts:f = open(i)for s in f.readlines():a = s.split(',')if(geodistance(float(a[2]),float(a[3]),dis[0],dis[1])<3000):print("%s经过了浦东机场"%i)shutil.copy(i, to_path)count+=1breakprint("共%d辆出租车经过浦东机场"%count)
经过筛选,有263条数据经过了浦东机场,还是比较可观的。
随后就开始前端展示的搭建,我的需求是网页里可以打开相对应的文本,随后绘制出一天中所有的路径,其中载客状态由不同颜色的线条表示。同时有一个可拖动的进度条,可以控制一天内的大致时间来观察其路径的具体方向。
首先是一个打开文件的按钮,为其绑定事件。
<input id='file' type="file" onchange="upload(this)" />
function upload(input) {//支持chrome IE10if (window.FileReader) {var file = input.files[0];console.log(file)filename = file.name.split(".")[0];var reader = new FileReader();reader.onload = function() {var arr = this.result.split("\n");arrData = arr;console.log(arr);map.clearOverlays(); drawLines(arr);}
// reader.readAsText(file,"UTF-8");reader.readAsText(file,"gb2312");}//支持IE 7 8 9 10else if (typeof window.ActiveXObject != 'undefined'){var xmlDoc;xmlDoc = new ActiveXObject("Microsoft.XMLDOM");xmlDoc.async = false;xmlDoc.load(input.value);alert(xmlDoc.xml);}//支持FFelse if (document.implementation && document.implementation.createDocument) {var xmlDoc;xmlDoc = document.implementation.createDocument("", "", null);xmlDoc.async = false;xmlDoc.load(input.value);alert(xmlDoc.xml);} else {alert('error');}
因为我使用的是chrome浏览器,所以只在其中一个分支里进行了逻辑处理,其他的兼容性分支也是类似的。
reader.onload = function() {var arr = this.result.split("\n");arrData = arr;console.log(arr);map.clearOverlays(); drawLines(arr);}
即载入文件后,就对百度地图的组件进行重绘,具体百度地图API的接入可参考代码或者百度的文档。
function drawLines(arr,p){p = p || 1.0;var t = arr[0].split(",");var lastLong = t[2];var lastLat = t[3];var isFull = 0;var lastFull = 0;var temp = [];for(var i = 0 ; i < arr.length*p - 1; i=i+1){var a = arr[i].split(",");if(a[2]<120||a[2]>122||a[3]<30||a[3]>33)continue;if(a[6]!=lastFull || i == arr.length - 2){var c = "green";if (lastFull==1){c = "red";}var polyline = new BMap.Polyline(temp, {strokeColor:c,strokeWeight:3, strokeOpacity:1});map.addOverlay(polyline);temp = [];temp.push(new BMap.Point(lastLong,lastLat))}temp.push(new BMap.Point(a[2],a[3]));lastLong = a[2];lastLat = a[3];lastFull = a[6];}}
逻辑也比较简单,对每行文本进行经纬度提取然后再通过BMap.Polyline()进行绘图,该API需要传入一个经纬度的数组和线条的样式。只不过需要注意的是,由于我想要路径颜色根据载客状态不同而不同,所以需要多段绘制。一开始图方便每两个点就进行一次绘图,但1700多个经纬度点就要绘图1700多次,导致网页非常卡顿。后来优化了一下,修改成每一段载客/空载进行一次绘图。
拖动条的样式和代码来自网络,具体也只是修改相应的回调函数,可参考代码。
完整代码
注:感谢网络上分享各组件代码的网友,同时因为是建模过程中写的,写的很忙乱,很多地方写的非常不美观,仅供学习参考。
<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><meta name="viewport" content="initial-scale=1.0, user-scalable=no" /><style type="text/css">body, html,#allmap {width: 100%;height: 100%;overflow: hidden;margin:0;font-family:"微软雅黑";}</style><script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=你的百度APIak码"></script><title>车辆运行轨迹测试</title>
<script src="http://c.cnzz.com/core.php"></script>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script><style>*{margin: 0;padding: 0;}.scroll{width: 400px;height: 8px;background-color: #ccc;margin: 10px;position: relative;}.bar{width: 10px;height: 22px;background-color: #369;position: absolute;top: -7px;left: 0;cursor: pointer;}.mask{width: 0;height: 100%;background-color: #336699;/*position: absolute;top: 0;left: 0;*/}</style></head>
<body><input id='file' type="file" onchange="upload(this)" /><div class="scroll" id="scrollBar"><div class="bar"></div><div class="mask"></div></div><div class="demo" id="demo"></div><div id="allmap"></div>
</body>
</html>
<script type="text/javascript">// 获取元素var scrollBar = document.getElementById("scrollBar");var bar = scrollBar.children[0];var mask = scrollBar.children[1];var demo = document.getElementById("demo");// 拖动原理bar.onmousedown = function(event){var event = event || window.event;var leftVal = event.clientX - this.offsetLeft;// 拖动放到down的里面var that = this;var p = 0.0;document.onmousemove = function(event){var event = event || window.event;that.style.left = event.clientX - leftVal + "px";// 限制条件var val = parseInt(that.style.left);if(val < 0){that.style.left = 0;}else if(val > 390){that.style.left = "390px";}// 移动的距离为遮罩的宽度mask.style.width = that.style.left;// 显示百分比p = parseInt(that.style.left) / 390;var hour = parseInt(p*24);var min = 24*60*p - hour*60;demo.innerHTML = "移动了:"+ parseInt(parseInt(that.style.left) / 390 * 100) + "%" +"约"+hour+":"+min;// 清除拖动 --- 防止鼠标已经弹起时还在拖动window.getSelection ? window.getSelection().removeAllRanges():document.selection.empty();map.clearOverlays();drawLines(arrData,p);}// 鼠标抬起停止拖动document.onmouseup = function(){document.onmousemove = null;//清空画布map.clearOverlays(); console.log("p:"+p)//根据比例绘图drawLines(arrData,p);}}var arrData = [];var linesPoints = null;// 百度地图API功能var map = new BMap.Map("allmap"); // 创建Map实例map.centerAndZoom(new BMap.Point(121.487500,31.374500), 15); // 初始化地图,设置中心点坐标和地图级别map.addControl(new BMap.MapTypeControl()); //添加地图类型控件map.setCurrentCity("上海"); // 设置地图显示的城市 此项是必须设置的map.enableScrollWheelZoom(true); //开启鼠标滚轮缩放function drawGreenLine(startLong,startLat,endLong,endLat){var polyline = new BMap.Polyline([new BMap.Point(startLong,startLat),//起始点的经纬度new BMap.Point(endLong,endLat)//终止点的经纬度], {strokeColor:"green",//设置颜色 strokeWeight:3, //宽度strokeOpacity:1});//透明度map.addOverlay(polyline);}function drawRedLine(){startLongR = endLongR;startLatR = endLatR;var polyline1 = new BMap.Polyline([new BMap.Point(startLongR,startLatR),//起始点的经纬度new BMap.Point(endLongR,endLatR)//终止点的经纬度], {strokeColor:"red",//设置颜色 strokeWeight:3, //宽度strokeOpacity:1});//透明度map.addOverlay(polyline1);}function drawLines(arr,p){p = p || 1.0;var t = arr[0].split(",");var lastLong = t[2];var lastLat = t[3];var isFull = 0;var lastFull = 0;var temp = [];for(var i = 0 ; i < arr.length*p - 1; i=i+1){var a = arr[i].split(",");if(a[2]<120||a[2]>122||a[3]<30||a[3]>33)continue;if(a[6]!=lastFull || i == arr.length - 2){var c = "green";if (lastFull==1){c = "red";}var polyline = new BMap.Polyline(temp, {strokeColor:c,strokeWeight:3, strokeOpacity:1});map.addOverlay(polyline);temp = [];temp.push(new BMap.Point(lastLong,lastLat))}temp.push(new BMap.Point(a[2],a[3]));lastLong = a[2];lastLat = a[3];lastFull = a[6];}}function upload(input) {//支持chrome IE10if (window.FileReader) {var file = input.files[0];console.log(file)filename = file.name.split(".")[0];var reader = new FileReader();reader.onload = function() {var arr = this.result.split("\n");arrData = arr;console.log(arr);map.clearOverlays(); drawLines(arr);}
// reader.readAsText(file,"UTF-8");reader.readAsText(file,"gb2312");}//支持IE 7 8 9 10else if (typeof window.ActiveXObject != 'undefined'){var xmlDoc;xmlDoc = new ActiveXObject("Microsoft.XMLDOM");xmlDoc.async = false;xmlDoc.load(input.value);alert(xmlDoc.xml);}//支持FFelse if (document.implementation && document.implementation.createDocument) {var xmlDoc;xmlDoc = document.implementation.createDocument("", "", null);xmlDoc.async = false;xmlDoc.load(input.value);alert(xmlDoc.xml);} else {alert('error');}
}
</script>
效果演示
如图便为一个在机场排队等待载客的典型选择,其在6时左右载客到达机场,并等待排队约三小时后载客再度离开机场。
如图为载客至机场后放弃排队直接返回的典型选择,司机在9时50分左右载客至机场后立刻空载返回,并于10时40分左右在市区周围再次揽客载至其他地点。
【2019数模国赛C题】js+BaiduMap API实现上海浦东机场出租车行车路径可视化相关推荐
- 2021年数模国赛A题国二摘要及经验分享(回忆篇,附部分代码)
以2021年数模国赛A题为例,主要分享内容有:如何写好国赛摘要.部分解题思路和排版技巧.接下来,干货走起. 题目重述:" FAST "主动反射面的形状调节 中国天眼( FAST ) ...
- 2022数模国赛B题无人机第一题第一小问的简单编程
前言 2022年国赛B题是关于无人机定位的抽象模型,总体难度不大.接下来简单介绍一下第一题第一小问的程序实现,当时国赛仓促,写的比较简略,仅供参考. 背景介绍 无源定位 第一个关键词是无源定位,无源定 ...
- 2022年数模国赛C题(岭回归、区间预测、矩阵热力图、Fisher判别分类模型)——总结心得(附最后一次数模经历,Matlab\SPSS\Lingo的理解综合)
文章目录 一.国赛 二.国赛代码展示 1.1 问题一 1.2 问题二 1.3 问题三 1.4 问题四 三.对于软件的理解 3.1 Matlab 3.1.1 表格的读取 3.1.2 元胞数组的相关函数的 ...
- [刨根问底] 五分钟搞懂组合评价模型—模糊Borda (以2021 年大学生数模国赛C题为例)
组合评价模型-模糊Borda(Matlab) 我们的征途是星辰大海,而并非烟尘人间. 目录 组合评价模型-模糊Borda(Matlab) 一.模糊Borda法简介 二.模糊Borda法主要步骤 (1) ...
- 2020数模国赛c题论文latex
一个新手小组的论文,记录第一篇 \documentclass{ctexart} % \documentclass[12pt, a4paper]{article} \usepackage{url}\us ...
- 2021数模国赛A题
A 题 "FAST"主动反射面的形状调节 中国天眼--500 米口径球面射电望远镜(Five-hundred-meter Aperture Spherical radio Tele ...
- 数据科学导论大作业:数模国赛C题(古代玻璃文物分类)
本来只是学习阶段的一次大作业,但是自己毕竟苦苦搜寻学习了好几天.不在这个世界上留下点记录觉得对不起自己的劳动成果(不是).于是乎有了这篇文章.顺带当作业报告写一写. 940131 目录 一.问题重述 ...
- 2021数模国赛C题
C 题 生产企业原材料的订购与运输 某建筑和装饰板材的生产企业所用原材料主要是木质纤维和其他植物素纤维材料,总体可分为 A,B,C 三种类型.该企业每年按 48 周安排生产,需要提前制定 24 周的原 ...
- 2021数模国赛D题
D 题 连铸切割的在线优化 连铸是将钢水变成钢坯的生产过程,具体流程如下(图 1):钢水连续地从中间包浇入结晶器,并按一定的速度从结晶器向下拉出,进入二冷段.钢水经过结晶器时,与结晶器表面接触的地方形 ...
最新文章
- Linux笔记 软件管理
- R语言使用ggplot2包的快速可视化函数qplot绘制散点图(设置每个数据点的文本标签信息)实战
- java 运算顺序 从左到右_java – 表达式与运算符优先级的从左到右的评估.为什么从左到右的评估似乎胜出了?...
- spark sql 本地调试_Spark精华问答|Spark的三种运行模式有何区别?
- 50 道 CSS 基础面试题及答案
- seajs的CMD模式的优势以及使用
- 登录页面跳出框架的JS
- android 网页json数据传输,如何将JSON格式的数据从WebView传递到HTML页面
- linux启动中继服务器失败,Tor中继服务器在Linux里安装配置的流程
- python:制作水印图片
- 还原精灵还原了mysql怎么办
- python 怎么import自己写的py模块
- PMP十五至尊图(第六版)
- keyshot9怎么导入材质_keyShot 9如何使用?keyshot 入门教程详解
- CSS的鼠标为手形: cursor:pointer;
- 文摘 - 巧取老山参
- C++创建型模式-原型模式
- 文件修复软件winhex
- Oracle Spatial的空间查询,代码操作
- python迭代器面试题_2018年最常见的Python面试题答案(下)