编写基于dbscan的GPS数据热点区域分析(一)


首先,谈谈这个编写任务介绍。此次是在win下开发,后续项目会在linux下结合hadoop或spark开发。这次要实现以下几点:


1. 能够将GPS数据在地图上呈现出来
2. 编写dbscan算法
3. 根据dbscan算法将GPS数据点分簇。并且在地图上用不同颜色标记各个簇。

4. 绘制地图围栏,也就是绘制每个簇形成的多边形

5. 给出一系列GPS数据,求出其经过密集区的顺序


在开发之前,我们需要明确用哪种地图,如果是用C#写,直接基于ArcGis Enginer二次开发倒是个不错的方法。不过,我决定用python来写,地图就用百度地图就行了。

本次开发涉及知识: 百度Map API调用 + PyQt4开发+ dbscan算法设计。所以这一篇,主要是讲讲百度地图API的相关使用和PyQt4的基本运用。百度地图我们选用js版本的API。我没学过js,所以就写写简单版本。 使用百度地图APi之前,需要去申请一个开发者ke。然后我们直接参考官网API来写。(点我)。。基本代码如下:

<!DOCTYPE html>
<html>

<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>
        基于DBSCAN的热点区域分析
    </title>
    <style type="text/css">
        html{height:100%;width:100%} body{height:100%;margin:0px;padding:0px;width:100%} #container{height:100%;width:100%}
    </style>
    <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js"></script>
    <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=你的key">
    </script>
</head>

<body>
<div id="container">
</div>
<script type="text/javascript" src="Mapv.js"></script>
<script type="text/javascript" src="GeoUtils_min.js"></script>
<script type="text/javascript">
    var map = new BMap.Map("container");
    var point = new BMap.Point(116.404, 39.915 );
    map.centerAndZoom(point, 10);
    addMapControl();
    enableScrollWheelZoom();

    function addMarker(latitude, longitude, iconPath) // 添加标记的函数
    {
        var pointTmp = new BMap.Point(longitude,latitude);
        map.centerAndZoom(pointTmp , 15);
        var marker = 0;
        if (iconPath=="")
            marker = new BMap.Marker(pointTmp); // 创建标注
        else {
            var myIcon = new BMap.Icon(iconPath, new BMap.Size(23, 25), {anchor: new BMap.Size(6, 20)});
            marker = new BMap.Marker(pointTmp, {icon: myIcon});
        }
        map.addOverlay(marker); // 将标注添加到地图中
    }

    function enableScrollWheelZoom() // 开启滚轮缩放
    {
        map.enableScrollWheelZoom();
    }
    function disbleScrollWheelZoom() // 关闭滚轮缩放
    {
        map.disableScrollWheelZoom();
    }
    function enableDoubleClickZoom()  // 开启双击放大
    {
        map.enableDoubleClickZoom();
    }
    function disableDoubleClickZoom()   // 关闭双击放大
    {
        map.disableDoubleClickZoom();
    }
    //地图控件添加函数:
    function addMapControl(){
        //向地图中添加比例尺控件
        var ctrl_sca = new BMap.ScaleControl({anchor:BMAP_ANCHOR_BOTTOM_LEFT});
        map.addControl(ctrl_sca);
    }
    function clearMarkers() {
        map.clearOverlays();
    }
</script>
</body>
</html>

我一开始绘点方法时,循环调用上面标记函数, 几百个数据倒是没问题,但是标记几十万个数据时就不行了。速度完全跟不上。后来用了下百度Mapv包。网址在这里,直接看吧。http://mapv.baidu.com/  作者已经给了很多歌例子了。看着调用就行了。下面给出效果图:



放大后:




接下来是第二个需要解决的问题,就是如何绘制地图围栏。这里我们通过查看api可以看到:


           看完之后容易了吧,我们要绘制围栏的时候,只要调用这个api就好了。不过,真正写起来可没那么好。我采用的方法是 先用js写围栏函数,参数是points 如下:

var fencingAreas = new Array();
    function getFencing(points) { // 参数是Array类型的 元素是Point
        // 实现: 通过一些列的点 生成多边形覆盖物(聚合区)
        // 把每次获取到的多边形 变量存放到fencingAreas变量当中
        var polygon = new BMap.Polygon(points);
        polygon.setStrokeColor("red");// 设置红色的边缘线
        polygon.disableMassClear(); // 禁止调用removeOvlays方法移除
        fencingAreas.push(polygon);
        map.addOverlay(polygon);
    }

这时候出现了个问题,怎么调用这个函数? PyQt4里面,我是采用QWebView来加载网页的。代码如下:

 def addFencing(self, points):
        """
        @brief: 生成地图围栏 其实就是绘制一个多边形
        :param points: 这个是list对象存放的数据 元素是DataObject类型的 表示点集合
        :return: None
        """
        js_order = "var tmp = new Array();var pointTmp =0;"
        for p in points:
            js_order += "pointTmp = new BMap.Point("+str(p.getLongitude())\
                        +","+str(p.getLatitude())+");tmp.push(pointTmp);"
        js_order += "getFencing(tmp);"
        self.__js(js_order)
        self.isFencing = True

其中 


    def __js(self, arg):#为减少重复代码量 封装成js私有函数
        self.webView.page().mainFrame().evaluateJavaScript(arg)
参数points是list类型的,我定义了GPS数据类,用来存放地图数据。


效果图如下:


在上图中,我是测试一个人的数据,黄色点事噪音点。另外两个围栏属于不同的簇。 效果满意吧? 接下来是如何判断一个点在这个地图围栏里面。说实话,百度API真的有点坑,找起来真麻烦。这里我提供地址:http://api.map.baidu.com/library/GeoUtils/1.2/docs/symbols/BMapLib.GeoUtils.html

<static> {Boolean} BMapLib.GeoUtils.isPointInPolygon(point, polygon)
判断点是否多边形内
参数:
{Point} point
点对象
{Polyline} polygon
多边形对象
返回值:
{Boolean} 点在多边形内返回true,否则返回false

就是上面这个函数。使用前,需要下载他的包。文件在你这里:  http://api.map.baidu.com/library/GeoUtils/1.2/src/GeoUtils_min.js 直接下载就好了。当然直接网络加载也没问题。我也直接和绘制围栏函数放一起了。代码如下:

   function  isInTheFencing(lng, lat){
        var point = new BMap.Point(lng, lat);
        for(var i=0;i<fencingAreas.length;i++) {
            var b = BMapLib.GeoUtils.isPointInPolygon(point, fencingAreas[i]);
            if (b == true) {
                return i;
            }
        }
        return -1;
    }

最后要测试GPS数据经过密集区的顺序。如果解决了上面的问题,这个问题就不是问题了。直接遍历下就好了。但是,这里说个小技巧,因为如果循环通过QWebView调用js必然耗时,有人说那我放到多线程里面处理不就行了吗? 错!你是通过QWebView来调用js的,已经涉及到UI了。切记不要在非UI线程里面调用UI。效果图如下:




接下来谈谈PyQt4的几个重点。因为我之前学过Qt开发,在PyQt里面,函数名,通信思想是一样的。不过涉及到信号和槽时,我还是折腾了会。这里简单说说PyQt4里面如何自定义信号和槽。

1) 如何编写槽函数:

    @QtCore.pyqtSignature("int")
    def fun(self, index):
        ......
      如上,定义槽函数时,先用装饰器来声明我这个是Qt的槽函数,并且它有个形参,参数是int类型的。。不要参数的话就留空“”。。顺带一提,那我要定义一个字符串类型的形参呢?? 这里需要留意下,是这样声明 
@QtCore.pyqtSignature("QString")
这个QString是Qt里面封装的字符串类。。

     那么如何定义一个信号呢??

_signal_clearMarkers = QtCore.pyqtSignal(int) 这里,把信号弄成了一个变量。 注意,字符串参数填写str
	
   最后一个问题:如何绑定信号和槽? 
 1)非自定义信号的绑定:
 self.connect(self.action_file_save_pic, QtCore.SIGNAL('triggered()'), \                           QtCore.SLOT('menuActionTriggered()'))
说明下,如果带参数,是填写类型而不是变量名。。。。
2)自定义信号的绑定:
  
self._signal_testOver.connect(self.slotTestOver)
   好了,ui部分就写到这里。下一篇,说说dbscan算法的代码实现。
  





  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值