气泡图中 y 位置的强制碰撞
Force collision for y position in bubble chart
我正在尝试使用 d3.forceSimulation 对图表圆圈的 y 位置施加力以防止它们重叠。
最终图表看起来像这样 -
我一直在关注一些示例,但无法以正确的方式调整 y 位置。不幸的是,我不知道哪里出了问题。任何正确方向的提示将不胜感激!
到目前为止,这是我的代码:
//ADDING SKELETON FOR THE CHART//
let width = 900;
let height = 300;
let margin = {x: 50, y:20};
let chartDiv = d3.select('body').append('div').attr('id', 'bubble-chart');
let svg = chartDiv.append('svg');
svg.attr('height', height).attr('width', width + margin.x);
//SCALES FOR X POSITION//
let posScale = d3.scaleLinear().domain([(0-overallMax), overallMax]);
posScale.range([0, width]);
//SCALES FOR COLOR//
let colorScale = d3.scaleOrdinal().domain(groupData.map(g=> g[0])).range(d3.schemeSet3);
//SCALE FOR CIRCLE SIZE//
let circleScale = d3.scaleLinear().domain([d3.min(data.map(d=> +d.total)), d3.max(data.map(d=> +d.total))])
.range([3, 10]);
//SIMULATION PART
let simulation = d3.forceSimulation().nodes(data)
.force('center', d=> d3.forceCenter(posScale(d.position), height/2))
//.force('charge', d3.forceManyBody().strength(.1))
.force('collision', d3.forceCollide().radius( d => circleScale(+d.total)))
.on('tick',ticked)
let circleGroup = svg.append('g').attr('transform', `translate(${margin.x / 2})`);
let circles = circleGroup.selectAll('circle').data(data).join('circle');
circles.attr('r', (d)=> circleScale(+d.total))//.attr('cx', (d) => posScale(d.position)).attr('cy', 50);
.attr("cx", d=> posScale(d.position))
.attr("cy", height / 2)
circles.attr('fill', (d)=> colorScale(d.category));
circles.style('opacity', '0.5');
// Apply these forces to the nodes and update their positions.
// Once the force algorithm is happy with positions ('alpha' value is low enough), simulations will stop.
function ticked(){
circles.attr("cy", d=> d.y).attr('cx', d=> posScale(d.position));
}
这是我的图表使用上面的代码后的样子:
提前致谢!
这不是创建蜂群图表(这种数据可视化的技术名称)的方式。您应该在模拟中使用 forceX
和 forceY
来设置位置。在你的情况下:
let simulation = d3.forceSimulation().nodes(data)
.force("x", d3.forceX(function(d) {
return posScale(d.position);
}).strength(foo))
.force("y", d3.forceY(50).strength(bar))
.force('collision', d3.forceCollide().radius( d => circleScale(d.total)))
.on('tick',ticked)
然后,根据需要调整强度(foo
和bar
),将ticked
函数改为使用x
和y
模拟提供的属性。
我正在尝试使用 d3.forceSimulation 对图表圆圈的 y 位置施加力以防止它们重叠。
最终图表看起来像这样 -
我一直在关注一些示例,但无法以正确的方式调整 y 位置。不幸的是,我不知道哪里出了问题。任何正确方向的提示将不胜感激!
到目前为止,这是我的代码:
//ADDING SKELETON FOR THE CHART//
let width = 900;
let height = 300;
let margin = {x: 50, y:20};
let chartDiv = d3.select('body').append('div').attr('id', 'bubble-chart');
let svg = chartDiv.append('svg');
svg.attr('height', height).attr('width', width + margin.x);
//SCALES FOR X POSITION//
let posScale = d3.scaleLinear().domain([(0-overallMax), overallMax]);
posScale.range([0, width]);
//SCALES FOR COLOR//
let colorScale = d3.scaleOrdinal().domain(groupData.map(g=> g[0])).range(d3.schemeSet3);
//SCALE FOR CIRCLE SIZE//
let circleScale = d3.scaleLinear().domain([d3.min(data.map(d=> +d.total)), d3.max(data.map(d=> +d.total))])
.range([3, 10]);
//SIMULATION PART
let simulation = d3.forceSimulation().nodes(data)
.force('center', d=> d3.forceCenter(posScale(d.position), height/2))
//.force('charge', d3.forceManyBody().strength(.1))
.force('collision', d3.forceCollide().radius( d => circleScale(+d.total)))
.on('tick',ticked)
let circleGroup = svg.append('g').attr('transform', `translate(${margin.x / 2})`);
let circles = circleGroup.selectAll('circle').data(data).join('circle');
circles.attr('r', (d)=> circleScale(+d.total))//.attr('cx', (d) => posScale(d.position)).attr('cy', 50);
.attr("cx", d=> posScale(d.position))
.attr("cy", height / 2)
circles.attr('fill', (d)=> colorScale(d.category));
circles.style('opacity', '0.5');
// Apply these forces to the nodes and update their positions.
// Once the force algorithm is happy with positions ('alpha' value is low enough), simulations will stop.
function ticked(){
circles.attr("cy", d=> d.y).attr('cx', d=> posScale(d.position));
}
这是我的图表使用上面的代码后的样子:
提前致谢!
这不是创建蜂群图表(这种数据可视化的技术名称)的方式。您应该在模拟中使用 forceX
和 forceY
来设置位置。在你的情况下:
let simulation = d3.forceSimulation().nodes(data)
.force("x", d3.forceX(function(d) {
return posScale(d.position);
}).strength(foo))
.force("y", d3.forceY(50).strength(bar))
.force('collision', d3.forceCollide().radius( d => circleScale(d.total)))
.on('tick',ticked)
然后,根据需要调整强度(foo
和bar
),将ticked
函数改为使用x
和y
模拟提供的属性。