Elips zarf verilerinin D3 haritasını oluşturma


16

Elips, daha özel olarak elips "zarflar" olan bu veri kümesi var. Birinin bunları bir D3 haritasında nasıl çizebileceğim konusunda tavsiyeye sahip olup olmadığını merak ediyordum. Mercator projeksiyonlu bir harita kurulumum zaten var. Bu stackoverflow cevabı beni yakınlaştıran bir createEllipse işlevi vardır, ancak verileri doğru yorumladığımdan emin olmak istiyorum.

Verilerden elipsin büyük / küçük eksen değerlerini taktım ve rotasyon için azimut kullandım, bu doğru olur mu? "Zarf" kısmını da gerçekten anlamıyorum. Her bölgedeki birkaç elips nasıl tek bir bitişik şekil oluşturur?

Herhangi bir tavsiye mutluluk duyacağız.

resim açıklamasını buraya girin

  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>

Yanıtlar:


1

Sonuçları neredeyse doğru yorumladığınız anlaşılıyor.

Çözdüğüm bir hata, kodunuzun azimutu dikkate almamasıdır.

Başka bir olası sorun eksenlerle ilgili olabilir. Sağlanan tabloda, bir elips boyutu gibi ses çıkaran "eksen boyutları" olarak adlandırılırken, createEllipse işlevi yarıçapları parametre olarak alır. Lütfen, yukarıda bahsedilen sorunların giderildiği görselleştirmede yakınlaştırılmış görüntüye bir göz atın . Fareyle üzerine gelindiğinde ipucu referans olarak eklenir.

Üçüncü sorun tartışmalıdır ve tabloda oluşturulan veri formatına bağlıdır. Yani x her zaman boylam ve y - enlem anlamına gelmez. Ancak mantıksal olarak daha uzun değerlerin ("x" değerleri daha büyük veya "y" değerlerine eşit) yatay yöne karşılık gelmesi gerektiği anlaşılmaktadır.

Bir yan not olarak: görselleştirmenin hassasiyeti de yaklaşık Dünya yarıçapının kullanımından etkilenir, ancak bu küçüktür.

Burada "zarf" ile ifade edilen alan değerlerinin elips alanından çok daha küçük olduğu göz önüne alındığında, muhtemelen elips içeride bulunan belirli bir ilgi alanını kuşatmaktadır.


Bu çok yardımcı olur. Yanıt ve kod örneği için teşekkür ederiz! Veri kümesi hakkında daha fazla bilgi alıyorum. (Düşen roket enkazına ilişkin veriler) Yani, zarfın tüm elipslerin bulunduğu bölge olduğuna inanıyorum.
jrue
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.