Home > database >  I want to get dot chart customize
I want to get dot chart customize

Time:11-03

I'm learning d3 charts and I want to get the result like the image. The data is json and it looks like this:

[{
    "date": "2020.12.1",
    "pay": 1    
},
{
    "date": "2021.1.2",
    "pay": 1    
},
{
    "date": "2021.2.1",
    "pay": 1    
},
...

pay = 1 //on time,
pay = 2 // missed,
pay = 3 // no data

Thanks regard.

result Image

CodePudding user response:

Here's an example. For simplicity, I've hard coded the positions of entries in the color legend. In practice, it may be better to do the color legend in HTML so that you can take advantage of automatic horizontal layout.

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <script src="https://d3js.org/d3.v7.js"></script>
</head>

<body>
  <div id="chart"></div>

  <script>
    /* --- set up --- */

    const margin = { top: 10, bottom: 50, left: 10, right: 10 };

    const width = 500 - margin.left - margin.right;
    const height = 140 - margin.top - margin.bottom;

    const svg = d3.select('#chart')
      .append('svg')
        .attr('width', width   margin.left   margin.right)
        .attr('height', height   margin.top   margin.bottom);

    const g = svg.append('g')
        .attr('transform', `translate(${margin.left},${margin.top})`);

    /* --- data --- */

    const parseTime = d3.timeParse('%Y.%-m.%-d');

    const data = [
      { date: "2015.1.1", pay: 1 },
      { date: "2015.2.1", pay: 2 },
      { date: "2015.3.1", pay: 1 },
      { date: "2015.4.1", pay: 2 },
      { date: "2015.5.1", pay: 1 },
      { date: "2015.6.1", pay: 3 },
      { date: "2015.7.1", pay: 1 },
      { date: "2015.8.1", pay: 3 },
      { date: "2015.9.1", pay: 3 },
      { date: "2015.10.1", pay: 1 },
      { date: "2015.11.1", pay: 2 },
      { date: "2015.12.1", pay: 3 },
      { date: "2016.1.1", pay: 1 },
      { date: "2016.2.1", pay: 3 },
      { date: "2016.3.1", pay: 3 },
      { date: "2016.4.1", pay: 3 },
      { date: "2016.5.1", pay: 2 },
      { date: "2016.6.1", pay: 2 },
      { date: "2016.7.1", pay: 2 },
      { date: "2016.8.1", pay: 1 },
      { date: "2016.9.1", pay: 3 },
      { date: "2016.10.1", pay: 3 },
      { date: "2016.11.1", pay: 1 },
      { date: "2016.12.1", pay: 3 },
      { date: "2017.1.1", pay: 2 },
      { date: "2017.2.1", pay: 2 },
      { date: "2017.3.1", pay: 3 },
      { date: "2017.4.1", pay: 2 },
      { date: "2017.5.1", pay: 3 },
      { date: "2017.6.1", pay: 2 },
      { date: "2017.7.1", pay: 3 },
      { date: "2017.8.1", pay: 1 },
      { date: "2017.9.1", pay: 2 },
      { date: "2017.10.1", pay: 2 },
      { date: "2017.11.1", pay: 1 },
      { date: "2017.12.1", pay: 1 },
      { date: "2018.1.1", pay: 1 },
      { date: "2018.2.1", pay: 1 },
      { date: "2018.3.1", pay: 3 },
      { date: "2018.4.1", pay: 2 },
      { date: "2018.5.1", pay: 1 },
      { date: "2018.6.1", pay: 3 },
      { date: "2018.7.1", pay: 1 },
      { date: "2018.8.1", pay: 3 },
      { date: "2018.9.1", pay: 3 },
      { date: "2018.10.1", pay: 3 },
      { date: "2018.11.1", pay: 1 },
      { date: "2018.12.1", pay: 1 },
      { date: "2019.1.1", pay: 3 },
      { date: "2019.2.1", pay: 1 },
      { date: "2019.3.1", pay: 2 },
      { date: "2019.4.1", pay: 3 },
      { date: "2019.5.1", pay: 3 },
      { date: "2019.6.1", pay: 1 },
      { date: "2019.7.1", pay: 1 },
      { date: "2019.8.1", pay: 1 },
      { date: "2019.9.1", pay: 3 },
      { date: "2019.10.1", pay: 2 },
      { date: "2019.11.1", pay: 2 },
      { date: "2019.12.1", pay: 2 },
      { date: "2020.1.1", pay: 1 },
      { date: "2020.2.1", pay: 2 },
      { date: "2020.3.1", pay: 2 },
      { date: "2020.4.1", pay: 1 },
      { date: "2020.5.1", pay: 3 },
      { date: "2020.6.1", pay: 1 },
      { date: "2020.7.1", pay: 1 },
      { date: "2020.8.1", pay: 3 },
      { date: "2020.9.1", pay: 1 },
      { date: "2020.10.1", pay: 2 },
      { date: "2020.11.1", pay: 1 },
      { date: "2020.12.1", pay: 1 },
      { date: "2021.1.1", pay: 3 },
      { date: "2021.2.1", pay: 2 },
      { date: "2021.3.1", pay: 1 },
      { date: "2021.4.1", pay: 1 },
      { date: "2021.5.1", pay: 1 },
      { date: "2021.6.1", pay: 2 },
      { date: "2021.7.1", pay: 3 },
      { date: "2021.8.1", pay: 3 },
      { date: "2021.9.1", pay: 2 },
      { date: "2021.10.1", pay: 2 },
      { date: "2021.11.1", pay: 3 },
      { date: "2021.12.1", pay: 3 },
    ]
      // convert the date strings to Date objects
      .map(({ date, pay }) => ({ date: parseTime(date), pay }));

    // group the payments by year
    const groupedByYear = d3.group(data, d => d.date.getFullYear());

    /* --- scales --- */

    // scale to place the groups according to the year
    const x = d3.scaleBand()
        .domain(groupedByYear.keys())
        .range([0, width]);

    // scales to place the dots in a group

    const numRows = 3;
    const numCols = 4;

    const row = d3.scalePoint()
        .domain(d3.range(numRows))
        .range([0, height])
        .padding(1);

    const col = d3.scalePoint()
        .domain(d3.range(numCols))
        .range([0, x.bandwidth()])
        .padding(1);

    // color scale
    const color = d3.scaleOrdinal()
        .domain([1, 2, 3])
        .range(['DarkSlateGray', 'MediumVioletRed', 'Gainsboro']);

    /* --- draw circles --- */

    // add one group for each year
    const groups = g.selectAll('g')
      .data(groupedByYear)
      .join('g')
        .attr('transform', ([year, payments]) => `translate(${x(year)})`);

    // calculate max radius size
    const radius = (Math.min(row.step(), col.step()) / 2) - 2;

    // add circles
    groups.selectAll('circle')
      .data(([year, payments]) => payments)
      .join('circle')
        .attr('transform', (d, i) => {
          const rowIndex = Math.floor(i / numCols);
          const colIndex = i % numCols;
          return `translate(${col(colIndex)},${row(rowIndex)})`;
        })
        .attr('fill', d => color(d.pay))
        .attr('r', radius);

    /* --- add axis for year labels --- */

    const xAxis = d3.axisBottom(x).tickSize(0);

    g.append('g')
        // move to the bottom of the chart
        .attr('transform', `translate(0,${height})`)
        // add axis
        .call(xAxis)
        // remove baseline
        .call(g => g.select('.domain').remove())
        // increase font size of the labels
        .call(g => g.selectAll('text').attr('font-size', 14));

    /* --- add color legend --- */

    const fontSize = 14;

    const legendData = [
      {label: 'ON TIME', color: color(1), x: 0},
      {label: 'MISSED PAYMENT', color: color(2), x: 100},
      {label: 'NO DATA', color: color(3), x: 270},
    ];

    const legendCells = g.append('g')
        .attr('transform', `translate(${margin.left},${height   40})`)
      .selectAll('g')
      .data(legendData)
      .join('g')
        .attr('transform', d => `translate(${d.x})`);

    legendCells.append('circle')
        .attr('r', fontSize / 2)
        .attr('fill',  d => d.color);

    legendCells.append('text')
        .attr('dominant-baseline', 'middle')
        .attr('font-family', 'sans-serif')
        .attr('fill', 'black')
        .attr('font-size', fontSize)
        .attr('x', fontSize)
        .text(d => d.label);
  </script>
</body>

</html>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related