D3.js d3.v4:如何设置每个Math.PI的刻度/2

D3.js d3.v4:如何设置每个Math.PI的刻度/2,d3.js,D3.js,d3.v4中规定了以下内容: 要使用时间刻度每十五分钟生成一次滴答声,请执行以下操作: axis.tickArguments([d3.timeMinute.every(15)]); 是否有类似的方法可用于时间以外的值?我正在绘制正弦和余弦曲线,所以我希望刻度从-2*Math.PI开始,在2*Math.PI结束,在这些值之间,我希望每个Math.PI/2都出现一个刻度。当然,我可以显式地计算tick值并将其提供给tickValue方法;但是,如果有一种更简单的方法来实现这一点,如上面引用的与时间

d3.v4中规定了以下内容:

要使用时间刻度每十五分钟生成一次滴答声,请执行以下操作:

axis.tickArguments([d3.timeMinute.every(15)]);

是否有类似的方法可用于时间以外的值?我正在绘制正弦和余弦曲线,所以我希望刻度从-2*Math.PI开始,在2*Math.PI结束,在这些值之间,我希望每个Math.PI/2都出现一个刻度。当然,我可以显式地计算tick值并将其提供给tickValue方法;但是,如果有一种更简单的方法来实现这一点,如上面引用的与时间相关的示例中所述,我更愿意使用这种方法。

设置结束刻度并以线性刻度指定刻度的精确间距是一件令人头痛的事。原因是D3轴生成器的创建方式使记号自动生成并隔开。因此,对于那些不太在意定制的人来说,方便的东西对于那些想要精确定制的人来说可能是一件麻烦事

我这里的解决方案是一个技巧:创建两个刻度,一个线性刻度用于绘制数据,另一个刻度仅用于制作轴,并且可以随意设置其值。在这里,我选择一个
scalePoint()
作为顺序比例

大概是这样的:

var realScale = d3.scaleLinear()
    .range([10,width-10])
    .domain([-2*Math.PI, 2*Math.PI]);

var axisScale = d3.scalePoint()
    .range([10,width-10])
    .domain(["-2 \u03c0", "-1.5 \u03c0", "-\u03c0", "-0.5 \u03c0", "0",
        "0.5 \u03c0", "\u03c0", "1.5 \u03c0", "2 \u03c0"]);
不要介意
\u03c0
,那只是Unicode中的π(pi)

检查此演示,将鼠标悬停在圆圈上以查看其位置:

var宽度=500,
高度=150;
var数据=[-2,-1,0,0.5,1.5];
var realScale=d3.scaleLinear()
.范围([10,宽度-10])
.domain([-2*Math.PI,2*Math.PI]);
var axisScale=d3.scalePoint()
.范围([10,宽度-10])
.domain([“-2\u03c0”、“-1.5\u03c0”、“-\u03c0”、“-0.5\u03c0”、“0”、“0.5\u03c0”、“\u03c0”、“1.5\u03c0”、“2\u03c0”);
var svg=d3.选择(“正文”).追加(“svg”)
.attr(“宽度”,宽度)
.attr(“高度”,高度);
var circles=svg.selectAll(“circle”).data(数据)
.输入()
.附加(“圆圈”)
.attr(“r”,8)
.attr(“填充”、“teal”)
.attr(“cy”,50)
.attr(“cx”,功能(d){
返回realScale(d*Math.PI)
})
.附加(“标题”)
.文本(功能(d){
return“此圆位于“+d+”\u03c0”
});
var axis=d3.axisBottom(axisScale);
var gX=svg.append(“g”)
.attr(“转换”、“翻译(0100)”)
.呼叫(安讯士)

通过针对D3
tickValues
tickFormat
方法,我能够在程序控制(非手动布局)下以PI/2为单位实现x轴。调用
tickValues
以PI/2的间隔设置刻度。调用
tickFormat
生成适当的勾号标签。您可以在GitHub上查看完整的代码:

我的解决方案是定制tickValue和tickFormat。只需要1个刻度,委托函数就可以给出与Math.PI成比例的新值

const piChar = String.fromCharCode(960);
const tickFormat = val => {
    const piVal = val / Math.PI;
    return piVal + piChar;
};

const convertSIToTrig = siDomain => {
    const trigMin = siDomain[0] / Math.PI;
    const trigMax = siDomain[1] / Math.PI;
    return d3.ticks(trigMin, trigMax, 10).map(v => v * Math.PI);
};

const xScale = d3.scaleLinear().domain([-Math.PI * 2, Math.PI * 2]).range([0, 600]);

const xAxis = d3.axisBottom(xScale)
    .tickValues(convertSIToTrig(xScale.domain()))
    .tickFormat(tickFormat);

这样,如果您的xScale的域通过缩放/平移进行了更改,那么新的值将以较小/较大的间隔很好地生成

我对您的解决方案感到矛盾。它解决了我所说的特定问题。但我试图避免的是像您的那样手工编码输出:在这种情况下,恐怕简单的答案是“否”(是否有类似的方法可以用于时间以外的值?)。除此之外,让我问你:你确切地知道你想要显示什么值,但你不想硬编码它们。为什么?那就把我之前的评论删掉吧。下面是完整的评论,它回答了你的问题,我想:我对你的解决方案感到矛盾。它解决了我所说的特定问题。但我试图避免的是手动编码输出,如表达式中所示:[“-2\u03c0”、“-1.5\u03c0”、“-\u03c0”、“-0.5\u03c0”、“0”、“0.5\u03c0”、“\u03c0”、“1.5\u03c0”、“2\u03c0”);我希望d3能为我生成那个,或者至少生成间隔为pi/2的记号。这样,如果用户或编码器碰巧更改了域,所有内容都会自动调整。D3轴会自动调整,但不幸的是,不是您想要的方式。你可以做的是创建一个函数来设置域数组,就像我的回答一样,并使该函数自动调整。这听起来是可行的。谢谢你澄清情况。