如何在D3中绘制指定x定义域的二次函数y=-0.1x²+80图像
用D3绘制指定定义域的二次函数图像
嘿,我来帮你搞定这个D3画二次函数的问题!你之前考虑「生成函数路径上的大量点再连接」的思路完全正确,d3.arc确实不是干这个的——那玩意儿是用来画圆弧、扇形这类图形的,和函数曲线根本不搭边~
下面我一步步给你讲怎么实现,代码都是可直接运行的:
步骤1:搭建SVG画布基础框架
首先得创建一个SVG容器,设置好边距和尺寸,方便后续放图像和坐标轴:
// 设置画布的边距和实际绘图区域尺寸 const margin = {top: 20, right: 20, bottom: 30, left: 40}; const width = 600 - margin.left - margin.right; const height = 400 - 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})`);
步骤2:设置比例尺(关键!)
SVG的坐标系和我们数学里的不一样:SVG的y轴是向下递增的,所以得用比例尺把函数的数值(x、y)转换成SVG画布上的像素坐标。这里你可以直接替换成你需要的定义域起始/结束值:
// 这里替换成你想要的x起始和结束值,比如我设的是[-20, 20] const xDomain = [-20, 20]; // 根据你的二次函数y=-0.1x²+80,最大值是80,x在±20时y=0,所以y范围设[0,80] const yDomain = [0, 80]; // x轴用线性比例尺,把定义域映射到画布的宽度范围 const xScale = d3.scaleLinear() .domain(xDomain) .range([0, width]); // y轴同样用线性比例尺,注意range是反过来的(height到0),修正SVG的y轴方向 const yScale = d3.scaleLinear() .domain(yDomain) .range([height, 0]);
步骤3:生成函数的点数据集
我们需要在定义域内生成足够多的x值,然后计算每个x对应的y值——点越多,曲线越平滑:
// 用d3.range生成均匀分布的x值,步长设为0.5(你可以调小让曲线更丝滑) const xValues = d3.range(xDomain[0], xDomain[1], 0.5); // 遍历x值,计算对应的y值,整理成D3能识别的数组格式 const data = xValues.map(x => ({ x: x, y: -0.1 * Math.pow(x, 2) + 80 }));
步骤4:用线生成器绘制函数曲线
D3的d3.line就是专门用来把点数据转换成SVG路径的工具,我们用它来连接所有点:
// 创建线生成器,指定x、y坐标的映射规则 const line = d3.line() .x(d => xScale(d.x)) // 把数据里的x值转换成SVG的x像素坐标 .y(d => yScale(d.y)) // 把数据里的y值转换成SVG的y像素坐标 .curve(d3.curveLinear); // 线性连接点,也可以用curveBasis让曲线更平滑 // 把数据传给路径元素,绘制出曲线 svg.append("path") .datum(data) .attr("fill", "none") // 曲线不需要填充色 .attr("stroke", "steelblue") // 设置曲线颜色 .attr("stroke-width", 2) // 设置曲线粗细 .attr("d", line); // 用线生成器生成路径指令
步骤5:添加坐标轴(可选但推荐)
为了让图像更直观,加上x轴和y轴会清晰很多:
// 添加x轴,放在画布底部 svg.append("g") .attr("transform", `translate(0, ${height})`) .call(d3.axisBottom(xScale)); // 添加y轴,放在画布左侧 svg.append("g") .call(d3.axisLeft(yScale));
一些小Tips
- 如果你想要更平滑的曲线,可以把
curveLinear换成curveBasis或者curveMonotoneX,后者适合像你的二次函数这种先增后减的曲线,能保证单调性。 - 随时调整
xDomain的起始/结束值,只要对应的y值在yDomain范围内就行,如果y范围不确定,也可以用d3.extent自动计算:const yDomain = d3.extent(data, d => d.y); - 要是想给曲线加个渐变颜色或者动画,直接在路径元素上加对应的属性或过渡效果就好~
内容的提问来源于stack exchange,提问作者Canovice
相关产品推荐
相关产品推荐

