如何将Java返回的对象JSON数组传入D3构建多行折线图?
嘿,我来帮你搞定这个D3多行折线图的问题!你的数据格式需要先做一点转换,让D3更容易处理,然后一步步搭建图表就行,下面是详细步骤:
第一步:转换数据格式
当前的JSON数据是每个文件对应一组日期和数值数组,我们需要把它转换成每个数据点单独成对象的格式,这样D3处理起来更顺手:
// 你获取到的原始JSON数据 const rawData = [ {"date":["2017-12-18 13:31:02.0","2017-12-13 16:00:30.0","2017-12-18 13:30:46.0"],"fileName":"Google-1","noOfColumns":[12,22,54]}, {"date":["2017-12-18 13:29:27.0"],"fileName":"Yahoo-1","noOfColumns":[44]} ]; // 转换为D3友好的格式:每个数据点包含date、noOfColumns、fileName const processedData = []; rawData.forEach(fileItem => { fileItem.date.forEach((dateStr, index) => { processedData.push({ date: new Date(dateStr), // 转成Date对象,方便时间比例尺处理 noOfColumns: fileItem.noOfColumns[index], fileName: fileItem.fileName }); }); });
第二步:创建SVG容器与基础配置
先搭建好图表的画布框架,定义好边距和尺寸:
// 边距配置,避免内容贴到画布边缘 const margin = { top: 20, right: 80, bottom: 30, left: 50 }; const width = 800 - margin.left - margin.right; const height = 500 - margin.top - margin.bottom; // 向页面添加SVG容器 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})`);
第三步:定义比例尺与坐标轴
X轴是时间类型,用d3.scaleTime();Y轴是数值类型,用d3.scaleLinear():
// 提取所有日期和数值,用于设置比例尺的范围 const allDates = processedData.map(d => d.date); const allValues = processedData.map(d => d.noOfColumns); // X轴时间比例尺 const xScale = d3.scaleTime() .domain(d3.extent(allDates)) // 取数据中的最小和最大日期 .range([0, width]); // 映射到SVG的宽度范围 // Y轴数值比例尺 const yScale = d3.scaleLinear() .domain([0, d3.max(allValues)]) // 从0到数据中的最大列数 .range([height, 0]); // D3的Y轴是从上到下增长,所以range要反过来 // 添加X轴到SVG svg.append("g") .attr("transform", `translate(0, ${height})`) .call(d3.axisBottom(xScale)); // 添加Y轴到SVG svg.append("g") .call(d3.axisLeft(yScale)); // 添加X轴标签 svg.append("text") .attr("transform", `translate(${width/2}, ${height + margin.bottom - 5})`) .style("text-anchor", "middle") .text("日期"); // 添加Y轴标签 svg.append("text") .attr("transform", "rotate(-90)") .attr("y", 0 - margin.left) .attr("x", 0 - (height / 2)) .attr("dy", "1em") .style("text-anchor", "middle") .text("列数");
第四步:按文件名分组并绘制折线
用d3.group()把数据按文件名分组,再用线条生成器绘制每条折线:
// 按fileName对数据分组 const groupedData = d3.group(processedData, d => d.fileName); // 定义折线生成器,指定X、Y坐标的映射规则 const lineGenerator = d3.line() .x(d => xScale(d.date)) .y(d => yScale(d.noOfColumns)) .curve(d3.curveMonotoneX); // 可选参数,让折线更平滑 // 定义颜色比例尺,给每个文件名分配独特颜色 const colorScale = d3.scaleOrdinal() .domain(Array.from(groupedData.keys())) .range(d3.schemeCategory10); // 使用D3内置的分类色板 // 绘制每条折线 svg.selectAll(".line") .data(groupedData) .enter() .append("path") .attr("class", "line") .attr("d", d => lineGenerator(d[1])) // d[1]是当前分组的所有数据点 .attr("stroke", d => colorScale(d[0])) // d[0]是当前分组的fileName .attr("stroke-width", 2) .attr("fill", "none"); // 可选:绘制每个数据点的圆点,增强可读性 svg.selectAll(".dot") .data(processedData) .enter() .append("circle") .attr("class", "dot") .attr("cx", d => xScale(d.date)) .attr("cy", d => yScale(d.noOfColumns)) .attr("r", 4) .attr("fill", d => colorScale(d.fileName));
第五步:添加图例
添加图例让用户能区分不同折线对应的文件:
const legend = svg.selectAll(".legend") .data(groupedData.keys()) .enter() .append("g") .attr("class", "legend") .attr("transform", (d, i) => `translate(0, ${i * 20})`); // 按顺序排列图例项 // 添加图例颜色块 legend.append("rect") .attr("x", width - 18) .attr("width", 18) .attr("height", 18) .style("fill", d => colorScale(d)); // 添加图例文字 legend.append("text") .attr("x", width - 24) .attr("y", 9) .attr("dy", ".35em") .style("text-anchor", "end") .text(d => d);
内容的提问来源于stack exchange,提问作者ud1234
相关产品推荐
相关产品推荐

