【问题标题】:d3 line and points on map from csv data来自csv数据的地图上的d3线和点
【发布时间】:2017-12-21 03:56:20
【问题描述】:

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

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

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

我的问题是如何将 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>

【问题讨论】:

    标签: csv d3.js geojson


    【解决方案1】:

    你没有投射你的线:

    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 直接传递给路径(就像您为世界背景所做的那样),也就是说,如果您的数据在 geojson 中可用(尽管动态制作 geojson 并不难):

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

    这比直线更准确 - 在笛卡尔坐标空间中,d3.line 中直线之间的线段是直线或遵循预定义的曲线。 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 }
    

    【讨论】:

    • 非常感谢您的详细回答。你为我做了这么多细节真是太好了。我尝试了你的建议,他们确实回答了我的问题 - 我看到了如何从我的 csv lat lon 制作一个线串,但我得到的线不是我所希望的。我已经发布了另一个问题,所以希望你能再次帮助我。我确实有数据的 json 版本,我更喜欢使用它,但无法弄清楚如何将我的点转换为线串,我认为这正是我想要的。再次感谢
    • 其实我在这方面做了更多的工作,你的回答很完美。我没有看到预期结果的原因仅仅是与我的数据有关。我现在已经成功地使用了一些 json 来创建 geojson 并按照你的建议进行投影。再次感谢您的帮助。
    • 没问题,很高兴能提供帮助。
    猜你喜欢
    • 1970-01-01
    • 2016-03-01
    • 1970-01-01
    • 2015-06-03
    • 2014-01-09
    • 1970-01-01
    • 1970-01-01
    • 2020-09-21
    • 2023-03-30
    相关资源
    最近更新 更多