代码之家  ›  专栏  ›  技术社区  ›  user3471259

csv数据中地图上的d3线和点

  •  2
  • user3471259  · 技术社区  · 8 年前

    我试图绘制各个数据点,以及在这些点之间运行的线路径,如本例所示 D3 stop and restart transition along path to allow click through to geo data coordinates 我以前得到过帮助。

    现在我想使用实际数据,而不是坐标测试集,但遇到了麻烦。我已经为我的数据尝试了geoJson文件和csv。我正在使用一个csv文件,其中lon和lat用于点,并希望从同一组数据中生成线,即使用一组数据用于点和线。

    我无法将我的线路显示在正确的位置-它位于右上角,但应该位于/通过点。我认为这与投影有关,但我很难正确解析数据以获得所需的行字符串。我试着使用这里的样本 https://bl.ocks.org/alandunning/cfb7dcd7951826b9eacd54f0647f48d3 -但是获取空对象?? line in red points in yellow

    我的问题是如何将csv lon lat与d3 svg行生成器一起使用。 这是我的代码:

    <!DOCTYPE html>
    <html lang="en">
        <head>
    <meta charset="utf-8">
    <title>Working version 3</title>
    
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script src="https://d3js.org/d3-array.v1.min.js"></script>
    <script src="https://d3js.org/d3-geo.v1.min.js"></script>
    <script src="https://d3js.org/d3-queue.v3.min.js"></script>
    <script src="https://d3js.org/topojson.v1.min.js"></script>
    <style type="text/css">
    
    circle {
      fill: steelblue;
      stroke: pink;
      stroke-width: 3px;
    }
    
    
    .line{
      fill: none;
      stroke: red;
      stroke-width: 6;
    
    }
    
    </style>
    </head>
    <body>
    
    <script>
    
        var w = 960,
            h = 500;
    
        var projection = d3.geoMercator()
                             .translate([w/2, h/2])
                             .scale([w * 0.16]);
    
        var path = d3.geoPath()
                     .projection(projection);
    
        var duration = 10000;
    
        var svg = d3.select("body").append("svg")
            .attr("width", w)
            .attr("height", h);
    
    /*
        var line = d3.line()
                .x(function (d) {return projection([d.lon]);})
                .y(function (d) {return projection([d.lat]);})
        .curve(d3.curveBasis);
    
        var line = d3.line()
        .x(function(d){return projection(d[0].lon);})
        .y(function(d){return projection(d[0].lat);})
        .curve(d3.curveBasis);
    
    /*ok line shows up but in wrong place
        var line = d3.line()
        .x(function(d) { return (d.lon); })
        .y(function(d) { return (d.lat); })
            .curve(d3.curveBasis);
    */
    
    var line = d3.line()
        .x(function(d) { return (d.lon); })
        .y(function(d) { return (d.lat); })
        .curve(d3.curveBasis);
    
    
    //original
    /*
    var line = d3.line()
    .x(function(d){return projection(d)[0];})
    .y(function(d){return projection(d)[1];})
    .curve(d3.curveBasis);
    */
    //
    
    //bring in data
    d3.queue()
        .defer(d3.json, "data/oceans.json")
        .defer(d3.csv, "data/speckCities.csv")
        .await(ready);
    
    function ready (error, oceans, data){
        if (error) throw error;
    
        //console.log(data[0]);
        //console.log(data[0].lon);
    
    
    
    
    //map
    svg.selectAll("path")
            .data(oceans.features)
            .enter()
            .append("path")
            .attr("d", path)
            .style("fill", "#A8B2C3");
    
    var linepath = svg.append("path")
      .datum(data)
      .attr("d", line)
        .attr('class', 'line');
    
        svg.selectAll("circle")
             .data(data)
             .enter()
             .append("circle")
             .attr("cx", function(d) {
                 return projection([d.lon, d.lat])[0];
             })
             .attr("cy", function(d) {
                 return projection([d.lon, d.lat])[1];
             })
             .attr("r", 5)
             .style("fill", "yellow")
             .style("stroke", "gray")
             .style("stroke-width", 0.25)
             .style("opacity", 0.75)
             .append("title")           //Simple tooltip
             .text(function(d) {
                return d.name ;
             });
    
        //
    
    
    
    
        //
    
        /*svg.selectAll(".point")
          .data(coordinates)
            .enter()
            .append("circle")
          .attr("r", 7)
          .attr("transform", function(d) { return "translate(" + projection(d) + ")"; });
    
    
    var circle = svg.append("circle")
      .attr("r", 19)
      .attr("transform", "translate(" + projection(d) + ")");
    
    /*
    var pauseValues = {
            lastT: 0,
            currentT: 0
            };
    
    function transition() {
      circle.transition()
          .duration(duration - (duration * pauseValues.lastT))
          .attrTween("transform", translateAlong(linepath.node()))
          .on("end", function(){
            pauseValues = {
              lastT: 0,
              currentT: 0
            };
            transition()
          });
    }
    
    function translateAlong(path) {
      var l = path.getTotalLength();
      return function(d, i, a) {
        return function(t) {
          t += pauseValues.lastT;
          var p = path.getPointAtLength(t * l);
          pauseValues.currentT = t;
          return "translate(" + p.x + "," + p.y + ")";
        };
      };
    }
    
    d3.select('button').on('click',function(d,i){
      var self = d3.select(this);
      if (self.text() == "Pause"){
            self.text('Play');
            circle.transition()
          .duration(0);
            setTimeout(function(){
                pauseValues.lastT = pauseValues.currentT;
            }, 100);
      }else{
        self.text('Pause');
        transition();
      }
    });
    */
    }
    
    </script>
    </body>
    </html>
    
    1 回复  |  直到 8 年前
        1
  •  1
  •   Andrew Reid    8 年前

    您没有投射线条:

    var linepath = svg.append("path")
      .datum(data)
      .attr("d", line)
       .attr('class', 'line');
    

    在这种情况下,geojson中的经度/纬度对将转换为直像素坐标:

    var line = d3.line()
        .x(function(d) { return (d.lon); })
        .y(function(d) { return (d.lat); })
        .curve(d3.curveBasis);
    

    由于svg坐标从左上角的[0,0]开始,并且您的点看起来大约在东经10度左右(正经度)和北纬50度左右(正纬度),因此直线中的第一个点显示在距离左侧10个像素和距离顶部50个像素的位置。此外,由于svg y值随下移而增大,但纬度值随北移而增大(通常在地图上向上),因此与点相比,直线在y轴上也会出现反转。

    可以将直线函数设置为使用投影来设置x和y点:

    var line = d3.line()
        .x(function(d) { return projection([d.lon,d.lat])[0] ; })
        .y(function(d) { return projection([d.lon,d.lat])[1]; })
        .curve(d3.curveBasis);
    

    投影一个点需要纬度和经度,因此投影函数同时使用纬度和经度,并返回x和y,因此返回[0]和[1],这就是为什么注释掉的部分不起作用的原因

    但这是不必要的,您可以直接将geojson传递到路径(与您在world background中所做的相同),也就是说,如果您的数据在geojson中可用(尽管动态生成geojson并不困难):

    var linepath = svg.append("path")
      .datum(data) // in geojson form
      .attr("d", path)  // use your path 
      .attr('class', 'line');
    

    这比直线(d3中直线之间的线段)更精确。直线在笛卡尔坐标空间中是直线或沿着预定义的曲线。A d3。geoPath遵循大圆距离,因此点之间的线段遵循行星上最短的路径,这是一种更精确的表示,有时可能会认为不太符合风格。

    要动态创建geojson,假设您的数据如下所示: [{lon:number,lat:number},{lon:number,lat:number}] 您可以使用以下内容:

    var points = data.map(function(d) { return [d.lon,d.lat] })
    var geojson = { "type": "LineString", "coordinates": points }