在四边形区域绘制数据

时间:2017-02-22 09:09:13

标签: javascript d3.js scatter-plot

Red is the area where I will be plotting data

您好, 我正在通过d3.js数据绘图。下图提供了两个更好理解的示例。考虑到我试图在特定区域(红色区域)上绘制数据。在图1中,我很容易在d3中指定范围,

var x = d3.scale.linear().domain([a,b]).range([0, 100 ])
var y = d3.scale.linear().domain([a,b]).range([100, 0 ]) 

使用该范围,我可以在红色内的任何区域绘制数据,用于图一。

但同样的范围机制不能用于绘制第二图的红色区域,因为顶部的x值与底部的x值不同。

有没有办法指定d3的区域范围来在这些自定义形状上绘制数据?

1 个答案:

答案 0 :(得分:0)

这是一个非常有趣的问题。不幸的是,D3没有本地方法来做你想要的。但是,这可以创建自定义函数,根据x位置返回修改后的y位置。

有几种不同的方法可以做到这一点。在我的解决方案中,我将以这种格式传递给函数一个完整的对象:

{x: someValue, y: someValue}

您可能需要根据数据结构更改功能,这并不重要。这里重要的是一般的想法。

嗯,这是功能:

function calculateXPos(obj) {
    var verticalScale = d3.scaleLinear()
        .domain([0, 100])
        .range([0, 20]);

    var horizontalScale = d3.scaleLinear()
        .domain([0, 100]);

    horizontalScale.range([0 + (verticalScale(obj.y)), 100 - (verticalScale(obj.y))]);

    return horizontalScale(obj.x);
}

它做了什么?

解释

如您所见,该函数将参数作为参数,具有两个属性xy。使用线性D3刻度......

var verticalScale = d3.scaleLinear()
    .domain([0, 100])
    .range([0, 20]);

...该函数根据点的y位置计算范围的变化......

horizontalScale.range([0 + (verticalScale(obj.y)), 100 - (verticalScale(obj.y))]);

...并返回具有自定义范围的x位置:

return horizontalScale(obj.x); 

正如您所看到的,该函数中有许多硬编码值,如垂直标度的范围和水平标度中的差异(也作为范围)。同样,这只是为了证明一般的想法,价值可以改变。

现场演示

让我们看看它有效。第一步是在上述结构中创建数据。为此,我有这两个循环:

var data = [];

for (var i = 0; i < 11; i++) {
    for (var j = 0; j < 11; j++) {
        data.push({
            x: i * 10,
            y: j * 10
        });
    }
}

这会创建一个方阵。如果我们只是使用正常的常规D3比例绘制这些点,这就是我们得到的结果:

var svg = d3.select("svg");

var data = [];

for (var i = 0; i < 11; i++) {
    for (var j = 0; j < 11; j++) {
        data.push({
            x: i * 10,
            y: j * 10
        });
    }
}

var yScale = d3.scaleLinear()
    .domain([0, 100])
    .range([100, 0]);

var xScale = d3.scaleLinear()
    .domain([0, 100])
    .range([0, 100]);

var gX = svg.append("g").attr("transform", "translate(30,130)").call(d3.axisBottom(xScale).ticks(5));

var gY = svg.append("g").attr("transform", "translate(30,30)").call(d3.axisLeft(yScale).ticks(5));

var g = svg.append("g").attr("transform", "translate(30,30)");

var points = g.selectAll("foo")
    .data(data)
    .enter()
    .append("circle")
    .attr("fill", "firebrick")
    .attr("r", 2)
    .attr("cx", d => xScale(d.x))
    .attr("cy", d => yScale(d.y));
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>

但是,如果我们使用我们的函数(传递整个对象d),这就是我们得到的:

var svg = d3.select("svg");

var data = [];

for (var i = 0; i < 11; i++) {
    for (var j = 0; j < 11; j++) {
        data.push({
            x: i * 10,
            y: j * 10
        });
    }
}

var yScale = d3.scaleLinear()
    .domain([0, 100])
    .range([100, 0]);

var xScale = d3.scaleLinear()
    .domain([0, 100])
    .range([0, 100]);

var gX = svg.append("g").attr("transform", "translate(30,130)").call(d3.axisBottom(xScale).ticks(5));

var gY = svg.append("g").attr("transform", "translate(30,30)").call(d3.axisLeft(yScale).ticks(5));

var g = svg.append("g").attr("transform", "translate(30,30)");

var points = g.selectAll("foo")
    .data(data)
    .enter()
    .append("circle")
    .attr("fill", "firebrick")
    .attr("r", 2)
    .attr("cx", d => calculateXPos(d))
    .attr("cy", d => yScale(d.y));

function calculateXPos(obj) {
    var verticalScale = d3.scaleLinear()
        .domain([0, 100])
        .range([0, 20]);

    var horizontalScale = d3.scaleLinear()
        .domain([0, 100]);

    horizontalScale.range([0 + (verticalScale(obj.y)), 100 - (verticalScale(obj.y))]);

    return horizontalScale(obj.x);
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>

您在问题中描述的是梯形。