Home > OS >  D3 Pie Chart Not Returning Correct Data
D3 Pie Chart Not Returning Correct Data

Time:03-15

I've been working on a pie (donut) chart that compiles the 15 largest GDPs of 2021. It basically works fine in all but one way. I can't seem to get the correct country to appear when hovered over. Every piece of the chart returns Mexico. I know there is probably a less amateur and more efficient way than the 'if/else if' approach I've taken. Any help would be greatly appreciated.

You can view it here for reference. It's not in English but the code is understandable.

Note: the final 'else' statement returns Mexico which is why they all return Mexico.

The code in question is:

var country = [];
  
  var countryCorrespond = d3.selectAll(piePiece).datum.value;
    
    if (countryCorrespond === 22675271) {
      country.push('米国')
    } else if (countryCorrespond === 16642318) {
      country.push('中国')
    } else if (countryCorrespond === 5378136) {
      country.push('日本')
    } else if (countryCorrespond === 4319286) {
      country.push('ドイツ')
    } else if (countryCorrespond === 3124650) {
      country.push('イギリス')
    } else if (countryCorrespond === 3049704) {
      country.push('インド')
    } else if (countryCorrespond === 2938271) {
      country.push('フランス')
    } else if (countryCorrespond === 2106287) {
      country.push('イタリア')
    } else if (countryCorrespond === 1883487) {
      country.push('カナダ')
    } else if (countryCorrespond === 1806707) {
      country.push('韓国')
    } else if (countryCorrespond === 1710734) {
      country.push('ロシア')
    } else if (countryCorrespond === 1491772) {
      country.push('ブラジル')
    } else if (countryCorrespond === 1461552) {
      country.push('スペイン')
    } else {
      country.push('メキシコ')
    }

The entire code is:

const DATASET = [
  {'COUNTRY': '米国', 'GDP': 22675271},
  {'COUNTRY': '中国', 'GDP': 16642318},
  {'COUNTRY': '日本', 'GDP': 5378136},
  {'COUNTRY': 'ドイツ', 'GDP': 4319286},
  {'COUNTRY': 'イギリス', 'GDP': 3124650},
  {'COUNTRY': 'インド', 'GDP': 3049704},
  {'COUNTRY': 'フランス', 'GDP': 2938271},
  {'COUNTRY': 'イタリア', 'GDP': 2106287},
  {'COUNTRY': 'カナダ', 'GDP': 1883487},
  {'COUNTRY': '韓国', 'GDP': 1806707},
  {'COUNTRY': 'ロシア', 'GDP': 1710734},
  {'COUNTRY': 'オーストラリア', 'GDP': 1617543},
  {'COUNTRY': 'ブラジル', 'GDP': 1491772},
  {'COUNTRY': 'スペイン', 'GDP': 1461552},
  {'COUNTRY': 'メキシコ', 'GDP': 1192480}
];

var root = d3
    .hierarchy(DATASET)
    .eachBefore(function(val) {
         val.data.value = (val.parent ? val.parent.data.value   '.' : '')
    });

var colorScheme = d3
.scaleOrdinal()
.domain([DATASET.COUNTRY])
.range(['#33a02c', '#1f78b4', '#fdbf6f', '#A03363', '#ffff99', '#e31a1c', '#b2df8a', '#ff7f00', '#cab2d6', '#EDBC34', '#fb9a99', '#b15928', '#8DF7C9', '#a6cee3', '#6a3d9a']);

var height = 1000,
    width = 1000,
    margin = 50;

var radius = Math.min(width, height) / 2 - margin;

var svg = d3
  .select('.donut-chart')
  .append('svg')
  .attr('height', height)
  .attr('width', width)
  .append('g')
  .attr('transform', `translate(${width/2},${height/2})`);

var tooltip = d3
  .select('body')
  .append('div')
  .attr('class', 'tooltip');

var pie = d3.pie(root)
  .value(d => d[1]);

var GDPval = pie(Object.entries(DATASET.map(d => d.GDP)));

  svg
    .selectAll('path')
    .data(GDPval)
    .join('path')
    .attr('d', d3.arc()
         .innerRadius(160)
         .outerRadius(radius))
    .attr('fill', d => colorScheme(d))
    .attr('stroke', '#122B16')
    .attr('stroke-width', 2.5   'px')
    .style('opacity', 0.65);

var piePiece = 
    svg
      .selectAll('path')
      .selectAll('piece')
      .data(pie)
      .enter()
      .append('g')
      .attr('class', 'piece')

// console.log(piePiece);

var centralText = svg
  .append('text')
  .attr('dy', 0.35   'em')
  .attr('class', 'central-text')
  .attr('y', -10)
  .style('text-anchor', 'middle')
  .style('font-size', 50   'px')
  .text('GDP')

d3.selectAll('path')
  .on('mouseover', function(event, d) {
    d3.select(this)
      .style('opacity', 1)

  var country = [];
  
  var countryCorrespond = d3.selectAll(piePiece).datum.value;
    
    if (countryCorrespond === 22675271) {
      country.push('米国')
    } else if (countryCorrespond === 16642318) {
      country.push('中国')
    } else if (countryCorrespond === 5378136) {
      country.push('日本')
    } else if (countryCorrespond === 4319286) {
      country.push('ドイツ')
    } else if (countryCorrespond === 3124650) {
      country.push('イギリス')
    } else if (countryCorrespond === 3049704) {
      country.push('インド')
    } else if (countryCorrespond === 2938271) {
      country.push('フランス')
    } else if (countryCorrespond === 2106287) {
      country.push('イタリア')
    } else if (countryCorrespond === 1883487) {
      country.push('カナダ')
    } else if (countryCorrespond === 1806707) {
      country.push('韓国')
    } else if (countryCorrespond === 1710734) {
      country.push('ロシア')
    } else if (countryCorrespond === 1491772) {
      country.push('ブラジル')
    } else if (countryCorrespond === 1461552) {
      country.push('スペイン')
    } else {
      country.push('メキシコ')
    }
  
  centralText
      .text(country)
      .attr("y", -10);
    
    console.log(country)
  // }
   
  tooltip
    .text('$'   
          d3.select(this).datum().value)
    .html(tooltip.text().replace(/\B(?=(\d{3}) (?!\d))/g, ","));
          
  tooltip
    .style('visibility', 'visible')
    .style('left', event.pageX   28   'px')
    .style('top', event.pageY - 28   'px')
  })
.on("mousemove", function(d) {
      tooltip
    .style("left", event.pageX   28   "px")
    .style("top", event.pageY - 28   "px");
    })
 .on('mouseout', function() {
    tooltip
      .style('visibility', 'hidden')
      d3.select(this)
      .style('opacity', 0.65);
  
    centralText.text('GDP');
});

  d3
    .select('.source-info')
    .append('text')
.text("https://eleminist.com/article/1679 による")

Thanks for your help!

CodePudding user response:

Instead of generating the pie values with only the GDP values, use the whole DATASET object. That way the data generated by d3.pie() will have your original data inside .data, and each item is bound to the corresponding path so you can access that on mouseover, making it easy to use that data to show it in the tooltip and central text.

Code of interest below. Working codepen with all the code here.

var pies = d3.pie().value(d => d.GDP)(DATASET)

svg
  .selectAll('path')
  .data(pies)
  .join('path')
  .attr(
    'd',
    d3.arc().innerRadius(160).outerRadius(radius),
  )
 .on('mouseover', (event, d) => {
    tooltip
      .text('$'   d.data.GDP)
      .html(tooltip.text().replace(/\B(?=(\d{3}) (?!\d))/g, ','))

    tooltip
      .style('visibility', 'visible')
      .style('left', event.pageX   28   'px')
      .style('top', event.pageY - 28   'px')

    centralText.text(d.data.COUNTRY)
  })
  • Related