You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:56:27