创建加权热图的最简单方法

时间:2011-12-13 14:30:35

标签: language-agnostic data-visualization heatmap

考虑包含以下数据的CSV文件:

weight,lat,long
9876,23.44,88.15
1234,27.11,55.33
....

从这些数据创建加权热图的最简单方法是什么?

所有语言的答案均可接受。

2 个答案:

答案 0 :(得分:0)

使用matplotlib我能够让它工作:

import csv
import matplotlib
import matplotlib.pyplot as plt

with open('data.csv') as f:
    r = csv.reader(f)
    C, Y, X = zip(*r)

    X = [float(x) for x in X]
    Y = [float(y) for y in Y]

    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.hexbin(X, Y, C, gridsize=200)
    plt.show()

然而,gridsize=200的分辨率不够好,而且当使用更高的值时,matplotlib会在大约1000行的数据CSV文件中使用大量内存并且速度极慢。

似乎是hexbin() has performance issues已知的问题。

答案 1 :(得分:0)

这是我最近建立的类似地图的衍生产品...但是,在最多缩放级别,如果存在重叠,则会合并标记,因此您可能希望删除该功能。它还使用了5个“加热”步骤,这是上一步的两倍,因此您可能还想在那里进行一些更改。而且,如果您使用此文字代码,则会查找一些标记图标:1.png2.png ... 7.png

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Transaction Mapping</title>
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
<style>
#wrap {width:960px;margin-right:auto;margin-left:auto;position:relative;}
#map_canvas {width:100%;height:700px;}
#legend_values {position:relative; top:-700px; left:200px;}
table {border-collapse:collapse;}
</style>
</head>
<body>
<div id="wrap">
<?php
if (is_uploaded_file($_FILES['upfile']['tmp_name'])){
    $weights=array();
    $lats=array();
    $lngs=array();
    $hdr=(isset($_REQUEST["hdr"]))?$_REQUEST["hdr"]:$hdr=0;
    $file=$_FILES["upfile"]["tmp_name"];
    $data=fopen($file,'r');
    while($row=fgets($data)){
        str_replace("\n","",$row);
        str_replace("\r","",$row);
        if(strlen($row)>0){
            if($hdr<1){
                $cells=explode(",",$row);
                array_push($weights,$cells[0]);
                array_push($lats,$cells[1]);
                array_push($lngs,$cells[2]);
            }
            $hdr--;
        }
    }
    $c=0;?>
    <div id="map_canvas"></div>
    <div id="legend_values"></div>
    <script type="text/javascript">
    <?php 
    echo "var data=[";
    for($i=0;$i<count($weights);$i++){
        if($c>0){echo ",";}
        echo "[".$weights[$i].",".$lats[$i].",".$lngs[$i]."]";
        $c++;
    }
    echo "];\n";
    ?>
    var shopsToShow=Array();
    var openingWindow;
    var map;
    var placesToFilter=Array();
    var MyInfoWindow = new google.maps.InfoWindow({content: 'Loading...'});
    var bounds2 = new google.maps.LatLngBounds();
    var myOptions = {
        zoom: 9,
        mapTypeControl: false,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    for(i=0;i<data.length;i++){
        var a=new Object();
        a.weight=data[i][0];
        a.lat=data[i][1];
        a.lng=data[i][2];
        placesToFilter.push(a);
    }
    map = new google.maps.Map(document.getElementById('map_canvas'),myOptions);
    for(i=0;i<placesToFilter.length;i++){
        if(placesToFilter[i].lng!=0){
            var point2=new google.maps.LatLng(placesToFilter[i].lat,placesToFilter[i].lng);
            bounds2.extend(point2);
        }
    }
    google.maps.event.addListener(map, 'bounds_changed', function() {filterAnnotations();});
    map.fitBounds(bounds2);         

    function filterAnnotations(){

    for (x in shopsToShow) {
        shopsToShow[x].setMap(null);
        google.maps.event.clearListeners(shopsToShow[x], 'click');
    }
    shopsToShow=new Array();

    var found,checkingLocation;
    //20 in the below lines is the height and width of the graphic you're using for the marker
    scaleFactorLongitude = document.getElementById('map_canvas').offsetWidth/20; 
    scaleFactorLatitude = document.getElementById('map_canvas').offsetHeight/20;
    var bounds=map.getBounds();
    var latDelta=(bounds.getNorthEast().lat()-bounds.getSouthWest().lat())/scaleFactorLatitude;
    var longDelta=(bounds.getNorthEast().lng()-bounds.getSouthWest().lng())/scaleFactorLongitude;

    for (m=0; m<placesToFilter.length; m++) {
        checkingLocation=placesToFilter[m];
        checkingLatitude = checkingLocation.lat;
        checkingLongitude = checkingLocation.lng;

        found=false;
        for (x in shopsToShow) {
            if(Math.abs(shopsToShow[x].getPosition().lat()-checkingLatitude) < latDelta &&
               Math.abs(shopsToShow[x].getPosition().lng()-checkingLongitude) <longDelta ){
                shopsToShow[x].weight=(shopsToShow[x].weight*1)+(placesToFilter[m].weight*1);
                found=true;
                break;
            }
        }
        if ((!found)&&(checkingLongitude!=0)) {
            var point=new google.maps.LatLng(checkingLatitude,checkingLongitude);
            if (bounds.contains(point) == true){
                var marker = new google.maps.Marker({position: point,map: map, icon:'7.png'});
                marker.weight=placesToFilter[m].weight;
                shopsToShow.push(marker);
            }
        }
    }
    //adjust colors and clickability

    var maxweight=shopsToShow[0].weight*1;
    var minweight=shopsToShow[0].weight*1;
    for (i=1;i<shopsToShow.length;i++) {
        if (shopsToShow[i].weight*1>maxweight) {
            maxweight=shopsToShow[i].weight*1;
        }
        if (shopsToShow[i].count*1<minweight) {
            minweight=shopsToShow[i].weight*1;
        }
    }
        var gap=maxweight-minweight;
        var roundToNearest=10;
        if(gap<160){
            roundToNearest=5;
        }
        if(gap<16){
            roundToNearest=1;
        }
        //determine steps
        cat=[];
        var step=Math.ceil((gap/16)/roundToNearest)*roundToNearest;
        for(i=0;i<5;i++){
            var n=step*Math.pow(2,i);
            cat.push(n);
        }
        //Math.ceil(number/10)*10;
        if(gap==0){
            cat=[1,2,3,4,5];
        }

        document.getElementById('legend_values').innerHTML="<table id=\"nudge\"><tr><td align=\"center\" width=\"30px\" style=\"padding:3px 10px 3px 10px;background-color:#F0F;\">&le;"+cat[0]+"</td><td align=\"center\" width=\"30px\" style=\"padding:3px 10px 3px 10px; background-color:#0F0;\">&le;"+cat[1]+"</td><td align=\"center\" width=\"30px\" style=\"padding:3px 10px 3px 10px; background-color:#FF0;\">&le;"+cat[2]+"</td><td align=\"center\" width=\"30px\" style=\"padding:3px 10px 3px 10px; background-color:#F60;\">&le;"+cat[3]+"</td><td align=\"center\" width=\"30px\" style=\"padding:3px 10px 3px 10px; background-color:#F00;\">&le;"+cat[4]+"</td></tr></table>";
    document.getElementById('legend_values').style.left=((960-document.getElementById('nudge').offsetWidth*1)/2)+'px';

    for (var i = 0; i < shopsToShow.length; i++) {
        var marker = shopsToShow[i];
        var ic;
        //here you're setting the proper icons, so if you were to keep this as is, you'd need to have 7.png, 6.png, etc
        if(marker.weight<cat[4]){ic=7;}
        if(marker.weight<cat[3]){ic=6;}
        if(marker.weight<cat[2]){ic=5;}
        if(marker.weight<cat[1]){ic=4;}
        if(marker.weight<cat[0]){ic=1;}
        marker.setIcon(ic+".png");
        google.maps.event.addListener(marker, 'click', function () {
            MyInfoWindow.setContent('Weight:'+this.weight);
            MyInfoWindow.open(map, this);
        });
    }
}
</script>
<?php   
}
else{?>
<form action="" method="post" enctype="multipart/form-data">
<table><tr><td align="right">File:</td><td><input type="file" name="upfile" id="file" /></td></tr>
<tr><td align="right">First Row is Header:</td><td><input type="checkbox" name="hdr" id="hdr" value="1"/></td></tr>
<tr><td colspan="2" align="center"><input type="submit" name="submit" value="Upload" /></td></tr></table>
</form>
<?php 
}
?>
</div>
</body>
</html>