Why isn't my text displaying in the svg axis l

2019-07-14 19:39发布

This is a scatterplot displaying beer by alcohol by volume (x) and IBU (y). I cannot get the axis labels to display. I checked the DOM, and the text is in the tree, but for some reason, it is not displaying on the screen.

For the y-label, the margins don't seem to be working, and for the x, it is positioned where I want it to be, but I simply cannot see any text.

const dataFiles = ['https://raw.githubusercontent.com/inspectordanno/beer_components/master/scatterplot/data/beers.csv', 'https://raw.githubusercontent.com/inspectordanno/beer_components/master/scatterplot/data/breweries.csv']; //data files to be parsed

const promises = []; //empty array which will contain the promises

dataFiles.forEach(url => {
  promises.push(d3.csv(url)); //this parses each csv file and pushes it to the array
});


//dimensions and margins of plot
const margin = {
    top: 10,
    right: 30,
    bottom: 30,
    left: 60
  },
  width = 960 - margin.left - margin.right,
  height = 500 - margin.top - margin.bottom,
  padding = 30;

const svg = d3.select('body')
  .append('svg')
  .attr('width', width)
  .attr('height', height);

Promise.all(promises).then(data => { //here, I am combining the two arrays in the promise into one big array of beer objects
  data[0].forEach(beer => {
    const breweryid = beer.brewery_id;
    data[1].forEach(brewery => {
      if (parseInt(breweryid) == parseInt(brewery.id)) {
        beer.brewery_name = brewery.name;
        beer.brewery_city = brewery.city;
        beer.brewery_state = brewery.state;
      }
    });
  });
  let beers = data[0]; //beer data

  const xScale = d3.scaleLinear()
    .domain([0, d3.max(beers, d => d.abv)])
    .range([padding, width - padding *2]);

  const yScale = d3.scaleLinear()
    .domain([0, d3.max(beers, d => d.ibu)])
    .range([height - padding, padding]);

  const xAxis = d3.axisBottom()
    .scale(xScale)
    .ticks(10) //ask steven
    .tickFormat(d3.format(',.1%'));

    const yAxis = d3.axisLeft()
      .scale(yScale)
      .ticks(10); //ask steven
      // .tickFormat

    svg.selectAll('circle')
      .data(beers)
      .enter()
      .append('circle')
      .attr('cx', d => {
        return xScale(d.abv);
      })
      .attr('cy', d => {
        return yScale(d.ibu);
      })
      .attr('r', 1)
      .attr('fill', 'steelblue')
      .on('mouseover', d => console.log(d))

    //Create X axis
    svg.append("g")
      .attr("class", "axis")
      .attr("transform", "translate(0," + (height - padding) + ")")
      .call(xAxis);

    //text label for x axis
    svg.append("text")
      .attr("transform", `translate(${(width/2)}, ${height + margin.top * 4})`)
      .style("text-anchor", "middle")
      .text("Alcohol by Volume");

      // text label for the y axis
    svg.append("text")
        .attr("transform", "rotate(-90)")
        .attr('y', 0 - margin.left * .75)
        .attr('x', 0 - (height/2))
        .style("text-anchor", "middle")
        .text("IBU")

    //Create Y axis
    svg.append("g")
      .attr("class", "axis")
      .attr("transform", "translate(" + padding + ",0)")
      .call(yAxis);

}) //end .then of promise
  .catch(err => console.log(err)); // catching error in promises
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <script src="https://d3js.org/d3.v5.min.js"></script>
    <script src="main.js" charset="utf-8"></script>
  </body>
</html>

标签: d3.js svg
1条回答
Juvenile、少年°
2楼-- · 2019-07-14 20:21

The way you're dealing with the margins, dimensions, paddings and translates makes little sense. For instance, you set the properties of the margin object, but your SVG has a width and height that simply subtracts those values.

I'm not personally neither a user nor a fan of that pattern (that Mike Bostock calls margin convention), but this is how you can do it:

First, set the margins, as you did, and define the width and height. Then, add the margins for setting the SVG dimensions:

.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)

Finally, append a <g> element, translating it using margin.left and margin.top:

.append("g")
.attr("transform", "translate(" + margin.left + ","+ margin.top + ")");

Here is your code with that change (and changing the translate for the axes as well):

const dataFiles = ['https://raw.githubusercontent.com/inspectordanno/beer_components/master/scatterplot/data/beers.csv', 'https://raw.githubusercontent.com/inspectordanno/beer_components/master/scatterplot/data/breweries.csv']; //data files to be parsed

const promises = []; //empty array which will contain the promises

dataFiles.forEach(url => {
  promises.push(d3.csv(url)); //this parses each csv file and pushes it to the array
});


//dimensions and margins of plot
const margin = {
    top: 10,
    right: 30,
    bottom: 200,
    left: 100
  },
  width = 960 - margin.left - margin.right,
  height = 500 - margin.top - margin.bottom;

const svg = d3.select('body')
  .append('svg')
  .attr('width', width + margin.left + margin.right)
  .attr('height', height + margin.top + margin.bottom)
  .append("g")
  .attr("transform", "translate(" + margin.left + ","+ margin.top + ")");

Promise.all(promises).then(data => { //here, I am combining the two arrays in the promise into one big array of beer objects
  data[0].forEach(beer => {
    const breweryid = beer.brewery_id;
    data[1].forEach(brewery => {
      if (parseInt(breweryid) == parseInt(brewery.id)) {
        beer.brewery_name = brewery.name;
        beer.brewery_city = brewery.city;
        beer.brewery_state = brewery.state;
      }
    });
  });
  let beers = data[0]; //beer data

  const xScale = d3.scaleLinear()
    .domain([0, d3.max(beers, d => d.abv)])
    .range([0, width]);

  const yScale = d3.scaleLinear()
    .domain([0, d3.max(beers, d => d.ibu)])
    .range([height, 0]);

  const xAxis = d3.axisBottom()
    .scale(xScale)
    .ticks(10) //ask steven
    .tickFormat(d3.format(',.1%'));

    const yAxis = d3.axisLeft()
      .scale(yScale)
      .ticks(10); //ask steven
      // .tickFormat

    svg.selectAll('circle')
      .data(beers)
      .enter()
      .append('circle')
      .attr('cx', d => {
        return xScale(d.abv);
      })
      .attr('cy', d => {
        return yScale(d.ibu);
      })
      .attr('r', 1)
      .attr('fill', 'steelblue')
      .on('mouseover', d => console.log(d))

    //Create X axis
    svg.append("g")
      .attr("class", "axis")
      .attr("transform", "translate(0," + (height) + ")")
      .call(xAxis);

    //text label for x axis
    svg.append("text")
      .attr("transform", `translate(${(width/2)}, ${height + margin.top * 4})`)
      .style("text-anchor", "middle")
      .text("Alcohol by Volume");

      // text label for the y axis
    svg.append("text")
        .attr("transform", "rotate(-90)")
        .attr('y', 0 - margin.left * .75)
        .attr('x', 0 - (height/2))
        .style("text-anchor", "middle")
        .text("IBU")

    //Create Y axis
    svg.append("g")
      .attr("class", "axis")
      .call(yAxis);

}) //end .then of promise
  .catch(err => console.log(err)); // catching error in promises
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <script src="https://d3js.org/d3.v5.min.js"></script>
    <script src="main.js" charset="utf-8"></script>
  </body>
</html>

查看更多
登录 后发表回答