Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
142 views
in Technique[技术] by (71.8m points)

javascript - Group line plotting in D3 with d3.group

I am working with a tidy-long data structure with three columns: date, ID, num_orders.

date          ID          num_orders
"2018-08-22"  1           3
"2018-08-23"  7           1
"2018-08-23"  10          1
"2018-08-23"  17          1
"2018-08-23"  19          1
.
.
.

I would like to plot a line for each ID with date and num_orders as the x- and y-axis respectively, using D3.js. I am using this as a model for what I am doing, but in that code, the author is using the nest() function, which is no longer used in v6 of D3; the method used now is group(). So my code now is:

const margin = { top: 10, right: 30, bottom: 30, left: 60 };
const width = 1000 - margin.left - margin.right;
const height = 600 - margin.top - margin.bottom;

const svg = d3.select('#my_dataviz')
    .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})`);
                
d3.json("./data.json")
    .then( function(data) {        
        const grouped_data = d3.group(data, d => d.ID);

        parseDate = d3.timeParse('%Y-%m-%d')
        const xScale = d3.scaleTime()
                        .domain(d3.extent(data, d => parseDate(d.date)))
                        .range([0, width]);
        svg.append('g')
            .attr('transform', `translate(0, ${height})`)
            .call(d3.axisBottom(xScale));
        
        const yScale = d3.scaleLinear()
                        .domain([0, d3.max(data, d => d.num_orders)])
                        .range([height, 0]);
        svg.append('g')
            .call(d3.axisLeft(yScale));

        const myColor = d3.scaleOrdinal()
                            .domain(grouped_data.keys())
                            .range(d3.schemeSet3);
        
        svg.selectAll('.line')
            .data(grouped_data)
            .enter()
            .append('path')
                .attr('fill', 'none')
                .attr('stroke', d => myColor(d.keys))
                .attr('stroke-width', 1.5)
                .attr('d', function(d){
                                return d3.line()
                                    .x(d => xScale(d.date))
                                    .y(d => yScale(d.num_orders))
                                    (d.values);
                });
    } )

So far I can get the axis with tick-marks to show up, but none of the lines are showing up, which makes me think the problem is in the final svg.selectAll('.line') statement. I'm pretty new to D3, so any guidance on this problem is appreciated. (And if you have any overall suggestions for my code, I also welcome this.)

question from:https://stackoverflow.com/questions/66054877/group-line-plotting-in-d3-with-d3-group

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

d3.line() is accepting arrays only, while d.values() is an iterator. By converting it into an array the problem is solved.

Notice that, on the snippet I removed the parseDate because I am generating data as Dates. You most likely will need to keep the parseDate

const margin = { top: 10, right: 30, bottom: 30, left: 60 };
const width = 1000 - margin.left - margin.right;
const height = 600 - margin.top - margin.bottom;

var x = d3.timeDays(new Date(2020, 06, 01), new Date(2020, 10, 30));
var y = Array.from({length: x.length}, Math.random).map(n => Math.floor(n * 10) + 5);
var data = x.map((v, i) => {
  return {
    "date": v,
    "id": Math.floor(Math.random() * (10 + 1)),
    "num_orders": y[i]
  };
});

const svg = d3.select('#my_dataviz')
    .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})`);


const grouped_data = d3.group(data, d => d.id);

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

const xScale = d3.scaleTime()
                .domain(d3.extent(data, d => d.date))
                .range([0, width]);
svg.append('g')
    .attr('transform', `translate(0, ${height})`)
    .call(d3.axisBottom(xScale));

const yScale = d3.scaleLinear()
                .domain([0, d3.max(data, d => d.num_orders)])
                .range([height, 0]);
svg.append('g')
    .call(d3.axisLeft(yScale));

const myColor = d3.scaleOrdinal()
                    .domain(grouped_data.keys())
                    .range(d3.schemeSet3);

const line = d3.line()
              .x(d => { return xScale(d.date); })
              .y(d => yScale(d.num_orders));

svg.selectAll('.line')
    .data(grouped_data)
    .enter()
    .append('path')
        .attr('fill', 'none')
        .attr('stroke', d => myColor(d[0]))
        .attr('stroke-width', 1.5)
        .attr('d', (d) => line(Array.from(d.values())[1]));
   
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.5.0/d3.min.js"></script>
<div id="my_dataviz"></div>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...