楕円エンベロープデータのD3マップの作成


16

楕円、より具体的には楕円「エンベロープ」を含むこのデータセットがあります。これらがD3マップにどのように描画できるかについて誰かがアドバイスをくれたのではないかと思っていました。メルカトル図法を使用したマップ設定をすでに持っています。このstackoverflowの回答にはcreateEllipse関数があり、これにより近づきましたが、データを正しく解釈していることを確認したいと思います。

データから楕円の主軸/副軸の値を差し込み、回転に方位角を使用しましたが、これは正しいでしょうか?「封筒」の部分もよくわかりません。各ゾーンのいくつかの楕円はどのようにして単一の連続した形状を作成しますか?

任意のアドバイスをいただければ幸いです。

ここに画像の説明を入力してください

  const margin  = {top:0, right:0, bottom:0, left:0},
        width   = 1000 - margin.left - margin.right,
        height  = 800  - margin.top - margin.bottom;

  const svg = d3.select('body')
      .append('svg')
      .attr('width', '100%')
      .attr('height', '100%')
      .attr('viewBox', `0 0 ${width + margin.left + margin.right} ${height + margin.top + margin.bottom}`);

  const chart = svg.append('g')
      .attr('transform', `translate(${margin.left},${margin.top})`);

  //a/b are ellipse axes, x/y is center
  const createEllipse = function createEllipse(a, b, x = 0, y = 0, rotation = 0) {
    let k = Math.ceil(36 * (Math.max(a/b,b/a))); // sample angles
    let coords = [];
    for (let i = 0; i <= k; i++) {
      let angle = Math.PI*2 / k * i + rotation;
      let r = a * b / Math.sqrt(a*a*Math.sin(angle)*Math.sin(angle) + b*b*Math.cos(angle)*Math.cos(angle));
      coords.push(getLatLong([x,y],angle,r));
    }
    return { 'type':'Polygon', 'coordinates':[coords] };
  }

  const getLatLong = function getLatLong(center,angle,radius) {
    let rEarth = 6371; // kilometers
    x0 = center[0] * Math.PI / 180; // convert to radians.
    y0 = center[1] * Math.PI / 180;
    let y1 = Math.asin( Math.sin(y0)*Math.cos(radius/rEarth) + Math.cos(y0)*Math.sin(radius/rEarth)*Math.cos(angle) );
    let x1 = x0 + Math.atan2(Math.sin(angle)*Math.sin(radius/rEarth)*Math.cos(y0), Math.cos(radius/rEarth)-Math.sin(y0)*Math.sin(y1));
    y1 = y1 * 180 / Math.PI;
    x1 = x1 * 180 / Math.PI;
    return [x1,y1];
  } 


  d3.json('https://media.journalism.berkeley.edu/upload/2019/11/kazakhstan.json').then((data) => {

      const ellipses = [
        {lat: 48.6,    lng: 64.7,     axis_x: 30, axis_y: 16, azimuth: 26.5, area_hectar: 0.0713,  zone: 'U1'},
        {lat: 48.625,  lng: 64.625,   axis_x: 30, axis_y: 16, azimuth: 26.5, area_hectar: 0.0713,  zone: 'U1'},
        {lat: 48.366,  lng: 65.44166, axis_x: 50, axis_y: 30, azimuth: 40,   area_hectar: 0.11775, zone: 'U2'},
        {lat: 48.85,   lng: 65.61666, axis_x: 20, axis_y: 22, azimuth: 29,   area_hectar: 0.17584, zone: 'U3'},
        {lat: 48.9333, lng: 65.8,     axis_x: 22, axis_y: 22, azimuth: 28,   area_hectar: 0.17584, zone: 'U3'},
        {lat: 48.9166, lng: 66.05,    axis_x: 50, axis_y: 20, azimuth: 38,   area_hectar: 0.17584, zone: 'U3'},
        {lat: 48.9166, lng: 65.68333, axis_x: 20, axis_y: 22, azimuth: 29,   area_hectar: 0.17584, zone: 'U3'},
        {lat: 49,      lng: 65.86666, axis_x: 22, axis_y: 22, azimuth: 29,   area_hectar: 0.17584, zone: 'U3'}
      ]

      const projection = d3.geoMercator()
        .fitExtent([[0,0],[width,height]], data)

      const path = d3.geoPath()
        .projection(projection);


      chart.selectAll('path')
        .data(data.features)
        .enter()
        .append('path')
        .attr('d',  path)
        .attr('stroke', 'black')
        .attr('strok-width', '1px')
        .attr('fill', 'none');

      chart.selectAll(".ellipses")
        .data(ellipses.map((d) => createEllipse(d.axis_x, d.axis_y, d.lng, d.lat, d.azimuth)))
        .enter()
        .append('path')
        .attr('d', path)
        .attr('stroke', 'black')
        .attr('stroke-width', '1px')
        .attr('fill', 'orange');

  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="chart"></div>

回答:


1

あなたは結果をほぼ正しく解釈しているようです。

私が修正した1つのエラーは、コードが方位角を考慮しないことです。

別の考えられる問題は、軸に関連している可能性があります。提供されている表では、それらは「軸の寸法」と呼ばれ、楕円の寸法のように聞こえますが、createEllipse関数は半径をパラメーターとして受け取ります。上記の問題が修正された、拡大された視覚化をご覧ください。ホバーのツールチップが参照用に追加されました。

3番目の問題は議論の余地があり、表で確立されたデータ形式に依存します。つまり、xは常に経度とy-緯度を意味するわけではありません。しかし、論理的には楕円の長い値( "x"の値は "y"の値よりも大きいか等しい)は水平方向に対応しているようです。

補足:視覚化の精度は、概算地球半径の使用によっても影響を受けますが、それは重要ではありません。

ここでの「エンベロープ」とは、指定された面積値が楕円の面積よりもはるかに小さいという事実を考慮して、楕円が内部にある特定の関心領域に外接することをおそらく意味します。


これは非常に役立ちます。返信とコードサンプルをありがとう!データセットに関する詳細情報を取得しています。(それは落下するロケットの破片に関するデータです)つまり、エンベロープはすべての楕円が含まれている領域だと思います。
jrue
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.