简体   繁体   中英

D3 Dates not showing on X-axis

Im trying to plot multiple lines on a chart. Im starting with plotting the axis, with x-axis havinh dates which are in the YYYY-MM-DD format and an experience score on the y axis. But for some reason, the dates on the x-axis dont show up, why is that? is there some formatting that i have to do before i put the data in d3.extent()?. Here is the raw data file ( https://raw.githubusercontent.com/QamarFarooq/data-for-testing/main/experience_scores.json )

图表未在 x 轴上显示日期

import React, {Component, useRef, useEffect} from 'react';
import ExperienceScoresData from './experience_scores';
import * as d3 from "d3";
import { select, csv, selectAll} from 'd3';
import { extent, max, min } from "d3-array";


ExperienceScoresData.map(function(val){
  val.customerExperienceScore *= 100;
  return 0;
})

class Linechart extends Component {
  constructor(props){
    super(props)
    this.createLineChart = this.createLineChart.bind(this)
  }

  metricToPercent (metric) {
    return (metric / 2 + 0.5) * 100;
  };

  scoreToDescrip (score) {
    if (score >= 0.6) {
      return "Good";
    } else if (score >= 0) {
      return "Average";
    } else {
      return "Poor";
    }
  };

  componentDidMount() {
    this.createLineChart()
  }

  componentDidUpdate() {
    this.createLineChart()
  }

  createLineChart() {
    var margin = {top: 85, right: 60, bottom: 60, left: 80},
        width = 960 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom;

    var node = this.node
    var divObj = select(node)
    var svgObj = divObj
                  .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 + ")");
    
    //Read the data
    d3.json("https://raw.githubusercontent.com/QamarFarooq/data-for-testing/main/experience_scores.json", function(data) {

      // group the data: I want to draw one line per group
      var sumstat = d3.nest() // nest function allows to group the calculation per level of a factor
        .key(function(d) { return d.companyBusinessName;})
        .entries(data);
      //console.log(sumstat)

      // Define the div for the tooltip
      var tooltip = divObj
        .append("div")  
        .attr("class","tooltip")
        .style("position", "absolute")
        .style("z-index", "10")
        .style("visibility", "hidden")
        .style("background-color", "white")
        .style("box-shadow","0 0 4px #000000")
        .style("padding", "10px")

      const monthNames = ["January", "February", "March", "April", "May", "June",
        "July", "August", "September", "October", "November", "December"];

      var d = new Date();

      tooltip.append("div")
      .attr("class", "tooltipDate")
      .html(monthNames[d.getMonth()] + " " + "(" + d.getFullYear() + ")")
      .style("font-size", "20px")
      .style("text-align","center")
        
      tooltip.append("div")
      .attr("class", "tooltipName")
      .style("text-align","center")
      .style("color","grey")

      tooltip.append("div")
      .attr("class", "tooltipTitle")
      .style("text-align","center")
      .html("Customer Sentiment")
      .style("padding-top","10px")

      tooltip.append("div")
      .attr("class", "tooltipScore")
      .style("text-align","center")
      .style("color",'DarkGrey')
      .style("font-size", "20px")

      tooltip.append("div")
      .attr("class", "tooltipPerception")
      .style("text-align","center")

   
      // Add title for linechart
      svgObj.append("text")
        .attr("text-anchor", "end")
        .attr("font-size", 25)
        .attr("x", 110)
        .attr("y", -50)
        .text("Customer Experience Score");      

      // Add X axis --> it is a date format
      var x = d3.scaleLinear()
        .domain(d3.extent(data, function(d) { return d.companyReviewDate; }))
        .range([ 0, width ]);
      svgObj.append("g")
        .attr("transform", "translate(0," + height + ")")
        .attr("stroke-width","0.3")
        .style("opacity","0.5")
        .call(d3.axisBottom(x).tickSize(-height).tickFormat('').ticks(5))
      
      // ticks
      svgObj.append("g")
      .style("opacity","0.7")
        .style("font", "14px times")
        .attr("transform", "translate(0," + height + ")")
        .call(d3.axisBottom(x).ticks(5));
        
      // Add Y axis  
      var y = d3.scaleLinear()
        .domain([0, d3.max(data, function(d) { return +d.customerExperienceScore; })])
        .range([ height, 0 ]);
      svgObj.append("g")
        .attr("stroke-width","0.3")
        .style("opacity","0.5")
        .call(d3.axisLeft(y).tickSize(-width).tickFormat('').ticks(5))
        
      // ticks
      svgObj.append("g")
      .style("opacity","0.7")
        .style("font", "14px times")
        .call(d3.axisLeft(y).ticks(5));

      // Add X axis label:
      svgObj.append("text")
        .attr("text-anchor", "end")
        .attr("font-size", 20)
        .attr("x", width/2 + margin.left)
        .attr("y", height + 50)
        .style("fill", d3.color("grey"))
        .text("Year Of Birth");

      // Add Y axis label:
      svgObj.append("text")
        .attr("text-anchor", "end")
        .attr("font-size", 20)
        .attr("transform", "rotate(-90)")
        .attr("x", -height/2 + 40)
        .attr("y", -margin.left + 25)
        .style("fill", d3.color("grey"))
        .text("N-Value")
        
      // color palette
      var key = sumstat.map(function(d){ return d.key }) // list of group names

      var color = d3.scaleOrdinal()
        .domain(key)
        .range(['#e41a1c','#377eb8','#4daf4a'])

      // Add one DOT in the legend for each name.
      svgObj.selectAll(".dots")
        .data(key)
        .enter()
        .append("circle")
          .attr("cx", function(d,i){ return 250 + i*120})
          .attr("cy", -30) 
          .attr("r", 7)
          .style("fill", function(d){ return color(d)})

      // Add LABEL for legends of each dot.
      svgObj.selectAll(".labels")
        .data(key)
        .enter()
        .append("text")
          .style("fill", d3.color("grey"))
          .attr("x", function(d,i){ return 270 + i*120})
          .attr("y", -28) 
          .text(function(d){ return d})
          .attr("text-anchor", "left")
          .style("alignment-baseline", "middle")
    })

    }
    render() {
      return <div ref={node => this.node = node} className="example_div"> </div>
   }
}

export default Linechart;

If data.companyReviewDate is a date, but you fetch it from JSON, you first need to parse it so it's recognised as a date. Otherwise, it's just a string - and scaleLinear doesn't do well with strings. So, to fetch it, use

data.forEach(function(d) {
    d.companyReviewDate = new Date(d.companyReviewDate);
});

Then, scaleLinear only thinks in numbers, not in dates. That means that even though it works with Dates, it sees it at the number of milliseconds since 01-01-1970, which is not very user friendly. Use scaleTime() instead!

 var divObj = d3.select(".example_div") var margin = { top: 85, right: 60, bottom: 60, left: 80 }, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; var svgObj = divObj .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 + ")"); //Read the data d3.json("https://raw.githubusercontent.com/QamarFarooq/data-for-testing/main/experience_scores.json", function(data) { // Transform `companyReviewDate` into an actual date data.forEach(function(d) { d.companyReviewDate = new Date(d.companyReviewDate); }); // group the data: I want to draw one line per group var sumstat = d3.nest() // nest function allows to group the calculation per level of a factor .key(function(d) { return d.companyBusinessName; }) .entries(data); console.log(sumstat) // Add title for linechart svgObj.append("text") .attr("text-anchor", "end") .attr("font-size", 25) .attr("x", 110) .attr("y", -50) .text("Customer Experience Score"); // Add X axis --> it is a date format var x = d3.scaleTime() .domain(d3.extent(data, function(d) { return d.companyReviewDate; })) .range([0, width]); svgObj.append("g") .attr("transform", "translate(0," + height + ")") .attr("stroke-width", "0.3") .style("opacity", "0.5") .call(d3.axisBottom(x).tickSize(-height).tickFormat('').ticks(5)) // ticks svgObj.append("g") .style("opacity", "0.7") .style("font", "14px times") .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(x).ticks(5)); // Add Y axis var y = d3.scaleLinear() .domain([0, d3.max(data, function(d) { return +d.customerExperienceScore; })]) .range([height, 0]); svgObj.append("g") .attr("stroke-width", "0.3") .style("opacity", "0.5") .call(d3.axisLeft(y).tickSize(-width).tickFormat('').ticks(5)) // ticks svgObj.append("g") .style("opacity", "0.7") .style("font", "14px times") .call(d3.axisLeft(y).ticks(5)); // Add X axis label: svgObj.append("text") .attr("text-anchor", "end") .attr("font-size", 20) .attr("x", width / 2 + margin.left) .attr("y", height + 50) .style("fill", d3.color("grey")) .text("Year Of Birth"); // Add Y axis label: svgObj.append("text") .attr("text-anchor", "end") .attr("font-size", 20) .attr("transform", "rotate(-90)") .attr("x", -height / 2 + 40) .attr("y", -margin.left + 25) .style("fill", d3.color("grey")) .text("N-Value") });
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script> <div class="example_div"></div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM