Krakenudo
Krakenudo

Reputation: 309

D3.js v5 Get data from value

I'm trying to take data from inside of some circles I've created, code rigth down. The circles have to contain this information, but I don't know if it contains it.

The code of the data in the circles is:

<script src="https://d3js.org/d3.v5.min.js"></script>
var year=1970
function typeClean(row){
  r = {}
  r.country = row.Country;
  r.continente = row.Continent;
  r.year = +row.Year;
  r.fertility = +row.fertility;
  r.esperanza = +row.life;
  r.population = +row.population;
  r.region = row.region;
  //return r;

    if(r.year==year){
        return r;
    }
 }

Then, I define some circles like this:

var colorScale = d3.scaleOrdinal(d3.schemeCategory10)
var chart = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
    chart.selectAll("body").data(datos).enter()
           .append("circle")
           .attr("cx", d => xScale(d.esperanza))
           .attr("cy", d => yScale(d.fertility))
           .attr("r", d => rScale(d.population))
           .attr("fill", d => colorScale(d.region))
           .attr("stroke", "#FFF")
           .attr("stroke-width", 1.5)
           .on("mouseover", function (d) {
               var thatCountry = ...;
           }
      )

circles by countries

What I'm trying to do is to find data inside of my circles if I have my mouse over the circle, but when the mouse exit this circle, the hover disapear. Then, with the data, I would like to put a text with the country and the population.

Now, all the code:

const totalWidth = 900;
const totalHeight = 420;

var margin = {top: 20, right: 10, bottom: 80, left: 90};
var width = totalWidth - margin.left - margin.right;
var height = totalHeight - margin.top - margin.bottom;

var svg = d3.select("body")
            .append("svg")
            .attr("width",totalWidth)
            .attr("height",totalHeight)

var year = 1970;

function typeClean(row){
  r = {}
  r.country = row.Country;
  r.continente = row.Continent;
  r.year = +row.Year;
  r.fertility = +row.fertility;
  r.esperanza = +row.life;
  r.population = +row.population;
  r.region = row.region;
  //return r;

    if(r.year==year){
        return r;
    }
 }



d3.csv("gapminder_data.csv",row => typeClean(row)).then(datos => {
//Scales
const xMax = d3.max(datos, d => d.esperanza)
const xScale = d3.scaleLinear().domain([30,82]).range([0, width])

const yMax = d3.max(datos, d => d.fertility)
const yScale = d3.scaleLinear().domain([0, 9]).range([height, 0])    

const rMax = d3.max(datos, d => d.population)
const rMin = d3.min(datos, d => d.population)
const rScale = d3.scaleSqrt().domain([rMin, rMax]).range([4, 25])

const xAxis = d3.axisBottom()
                .scale(xScale)
const yAxis = d3.axisLeft()
                .scale(yScale)
var colorScale = d3.scaleOrdinal(d3.schemeCategory10)

var chart = svg.append("g")
               .attr("transform", `translate(${margin.left},${margin.top})`);
    chart.append('g')
         .attr("transform", `translate(0,${height})`)
         .call(xAxis)
         .append("text")
         .text("Esperanza_vida")
         .attr("x",width/2)
         .attr("y",48)
         .attr("fill","black")
         .attr("class","axis")

    chart.append('g')
         .call(yAxis)
         .append("text")
         .text("Fertilidad")
         .attr("x",-78)
         .attr("y",-26)
         .attr("fill","black")
         .attr("class","axis")
         .attr("size",-30)
         .attr("transform","rotate(-90)");


    chart.selectAll("body").data(datos).enter()
         .append("circle")
         .attr("cx", d => xScale(d.esperanza))
         .attr("cy", d => yScale(d.fertility))
         .attr("r",d => rScale(d.population))
         .attr("fill", d => colorScale(d.region))
         .attr("stroke", "#FFF")
         .attr("stroke-width",1.5)
            .on("mouseover", function (d) {
            console.log(d)
           var thatCountry;
            })

})

Country,Year,fertility,life,population,child_mortality,gdp,region
Afghanistan,1964,7.671,33.639,10474903.0,339.7,1182.0,South Asia
Afghanistan,1965,7.671,34.152,10697983.0,334.1,1182.0,South Asia
Afghanistan,1966,7.671,34.662,10927724.0,328.7,1168.0,South Asia
Albania,1964,5.711,65.475,1817098.0,122.67,3023.0,Europe & Central Asia
Albania,1965,5.593999999999999,65.863,1869942.0,120.09,3129.0,Europe & Central Asia
Albania,1966,5.483,66.122,1922993.0,117.56,3242.0,Europe & Central Asia
Algeria,1964,7.653,47.953,11654905.0,247.3,5693.0,Middle East & North Africa
Algeria,1965,7.655,48.388999999999996,11923002.0,248.2,5916.0,Middle East & North Africa
Algeria,1966,7.657,48.806000000000004,12229853.0,248.9,5478.0,Middle East & North Africa
Angola,1964,7.425,34.604,5337063.0,305.2,4573.0,Sub-Saharan Africa
Angola,1965,7.43,35.007,5431135.0,297.55,4840.0,Sub-Saharan Africa
Angola,1966,7.422000000000001,35.41,5524090.0,289.99,5043.0,Sub-Saharan Africa

Upvotes: 0

Views: 1614

Answers (1)

Ian
Ian

Reputation: 34489

It's a little difficult to understand from your question, but it sounds like what you want to do is:

  • respond to some event e.g. mouseover
  • change the DOM in some way as a response

So firstly there is a mistake in your selection which is going to screw up the data binding, which is quite important for this. The following line:

chart.selectAll("body").data(datos).enter().append("circle")

Should read something more like:

chart.select("body").selectAll("circle").data(datos).enter().append("circle");

Essentially you should be calling selectAll for the thing you're going to append. You can stray from this pattern later for more advanced visualization.


To response to an event, you subscribe as you're doing, the first parameter d represents the datum or row of data you're bound to.

.on("mouseover", function(datum, index, elements) { 
    // datum can have additional information on
})

At this point I would typically manually modify the DOM. E.g. If I want some text to use as a tooltip for example. Note that instead of joining to circle you'd have to join to an svg:g and append the circles within it (because you can't add a text node in a circle).

.on("mouseover", function(datum) {
    // this represents the element selected
    d3.select(this)
      .append("text")
      .attr("class", "tooltip")
      .text(d => d.name);
});

Note that the cleanup is just as simple, on a mouseexit event you can strip out all text elements from the svg:g

d3.select(this)
  .selectAll("text")
  .remove();

Upvotes: 2

Related Questions