การสร้างแผนที่ D3 ของข้อมูลซองจดหมายวงรี


16

ฉันมีชุดข้อมูลนี้ซึ่งมีรูปวงรี "ซองจดหมาย" ที่เฉพาะเจาะจงยิ่งขึ้น ฉันสงสัยว่ามีใครบางคนมีคำแนะนำเกี่ยวกับวิธีการวาดเหล่านี้บนแผนที่ D3 ฉันมีการตั้งค่าแผนที่พร้อมฉายภาพ Mercator แล้ว คำตอบแบบสแต็คโอเวอร์โฟลว์นี้มีฟังก์ชั่น createEllipseซึ่งทำให้ฉันเข้าใกล้ แต่ฉันต้องการตรวจสอบให้แน่ใจว่าฉันกำลังตีความข้อมูลอย่างถูกต้อง

ฉันเสียบค่าแกนหลัก / รองของวงรีจากข้อมูลและใช้ azimuth สำหรับการหมุนนี่จะถูกต้องหรือไม่ ฉันไม่เข้าใจส่วน "ซองจดหมาย" ด้วย หลายจุดในแต่ละโซนจะสร้างรูปร่างที่ต่อเนื่องกันได้อย่างไร

คำแนะนำใด ๆ ที่จะได้รับการชื่นชม.

ป้อนคำอธิบายรูปภาพที่นี่

  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

ดูเหมือนว่าคุณกำลังตีความผลลัพธ์ที่ถูกต้อง

ข้อผิดพลาดอย่างหนึ่งที่ฉันแก้ไขคือรหัสของคุณไม่ถือว่าเป็นราบ

ปัญหาที่เป็นไปได้อื่นอาจเกี่ยวข้องกับแกน ในตารางหากมีการตั้งชื่อพวกเขาเป็น "ขนาดแกน" ซึ่งเสียงเหมือนมิติวงรีในขณะที่ฟังก์ชั่น createEllipse ใช้รัศมีเป็น params โปรดดูภาพการซูมด้วยภาพที่มีปัญหาข้างต้นได้รับการแก้ไข Tooltip on hover ถูกเพิ่มสำหรับการอ้างอิง

ปัญหาที่สามสามารถตรวจสอบได้และขึ้นอยู่กับรูปแบบข้อมูลที่กำหนดในตาราง ฉันหมายความว่า x ไม่ได้หมายถึงลองจิจูดและ y - ละติจูดเสมอไป แต่ตามหลักเหตุผลแล้วดูเหมือนว่าจุดไข่ปลาที่มีความยาวมากกว่าค่า ("x" คือค่าที่มากกว่าหรือเท่ากับ "y") ควรสอดคล้องกับทิศทางแนวนอน

ในฐานะที่เป็นหมายเหตุด้าน: ความแม่นยำของการสร้างภาพยังได้รับผลกระทบจากการใช้รัศมีของโลกโดยประมาณ

โดย "ซองจดหมาย" ที่นี่อาจหมายถึงว่าวงรีล้อมรอบพื้นที่ที่น่าสนใจซึ่งอยู่ภายในโดยพิจารณาจากความจริงที่ว่าค่าพื้นที่ที่กำหนดมีขนาดเล็กกว่าพื้นที่ของวงรีมาก


สิ่งนี้ช่วยได้อย่างมาก ขอบคุณสำหรับการตอบกลับและตัวอย่างโค้ด! ฉันได้รับข้อมูลเพิ่มเติมเกี่ยวกับชุดข้อมูล (มันเป็นข้อมูลเกี่ยวกับเศษซากจรวดที่ตกลงมา) ดังนั้นฉันเชื่อว่าซองจดหมายเป็นภูมิภาคที่มีจุดไข่ปลาทั้งหมดอยู่
jrue
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.