Reputation: 2617
I have a swarm plot that shows ranges from 0
to 1
on a linear x axis and size via the SVG circle's radius attribute. Snippet below:
var margins = {top:20, bottom:300, left:100, right:100};
var height = 200;
var width = 900;
var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;
var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);
var graphGroup = svg.append('g')
.attr('transform', "translate("+margins.left+","+margins.top+")");
//var tsvData = d3.tsv('fmc-equity.tsv');
//tsvData.then(function(rawData) {
//var data = rawData.map(function(d) {
//return {fmc:d.fmc, pequity:+d.pequity, total:+d.total, rank:+d.rank}
//});
var data = [{'pequity': 1.0, 'total': 24902636438.0},
{'pequity': 1.0, 'total': 8204868902.0},
{'pequity': 1.0, 'total': 6658546024.0},
{'pequity': 1.0, 'total': 6126023357.0},
{'pequity': 1.0, 'total': 2193415702.0},
{'pequity': 1.0, 'total': 1734784625.0},
{'pequity': 1.0, 'total': 1296048848.0},
{'pequity': 1.0, 'total': 308649243.8},
{'pequity': 1.0, 'total': 295207349.3},
{'pequity': 1.0, 'total': 234857862.9},
{'pequity': 1.0, 'total': 156598861.9},
{'pequity': 1.0, 'total': 104983353.0},
{'pequity': 1.0, 'total': 63690617.76},
{'pequity': 1.0, 'total': 59401648.51},
{'pequity': 0.975623135, 'total': 14007871265.0},
{'pequity': 0.967237964, 'total': 1685804854.0},
{'pequity': 0.963917349, 'total': 293309822.9},
{'pequity': 0.934185443, 'total': 2917969779.0},
{'pequity': 0.933316698, 'total': 30102340057.0},
{'pequity': 0.915294851, 'total': 24722091961.0},
{'pequity': 0.913848269, 'total': 25585870482.0},
{'pequity': 0.913408996, 'total': 2991804061.0},
{'pequity': 0.892768552, 'total': 9977890414.0},
{'pequity': 0.845989331, 'total': 88124798828.0},
{'pequity': 0.829158756, 'total': 1180176138.0},
{'pequity': 0.827893585, 'total': 21493562671.0},
{'pequity': 0.815844492, 'total': 1141920435.0},
{'pequity': 0.793349904, 'total': 45529532260.0},
{'pequity': 0.784721035, 'total': 163020000000.0},
{'pequity': 0.778621751, 'total': 2758477982.0},
{'pequity': 0.776066588, 'total': 96073251741.0},
{'pequity': 0.752238939, 'total': 34388436875.0},
{'pequity': 0.742142911, 'total': 1406030271.0},
{'pequity': 0.740334287, 'total': 4711578569.0},
{'pequity': 0.738044554, 'total': 72969280487.0},
{'pequity': 0.728912674, 'total': 51810952821.0},
{'pequity': 0.723159895, 'total': 147101000000.0},
{'pequity': 0.717957188, 'total': 380923000000.0},
{'pequity': 0.702860894, 'total': 1971690322.0},
{'pequity': 0.700934687, 'total': 334084000000.0},
{'pequity': 0.684489847, 'total': 162390000000.0},
{'pequity': 0.679992279, 'total': 57956445277.0},
{'pequity': 0.669998233, 'total': 3758791332.0},
{'pequity': 0.667230968, 'total': 187355000000.0},
{'pequity': 0.653736462, 'total': 186999000000.0},
{'pequity': 0.650328323, 'total': 76326103402.0},
{'pequity': 0.642256236, 'total': 244641000000.0},
{'pequity': 0.642232384, 'total': 21058144224.0},
{'pequity': 0.634697091, 'total': 36845417753.0},
{'pequity': 0.625246046, 'total': 7505300217.0},
{'pequity': 0.622668225, 'total': 287937000000.0},
{'pequity': 0.615894348, 'total': 390042000000.0},
{'pequity': 0.614523365, 'total': 493581000000.0},
{'pequity': 0.610259063, 'total': 187658000000.0},
{'pequity': 0.606075625, 'total': 20568282534.0},
{'pequity': 0.566893948, 'total': 13561590623.0},
{'pequity': 0.562164622, 'total': 1752893048.0},
{'pequity': 0.548193052, 'total': 54080529801.0},
{'pequity': 0.547672307, 'total': 333058000000.0},
{'pequity': 0.503813337, 'total': 61882066527.0},
{'pequity': 0.499762105, 'total': 549015425.1},
{'pequity': 0.492513345, 'total': 1922398097.0},
{'pequity': 0.482375439, 'total': 174165000000.0},
{'pequity': 0.481469613, 'total': 23194895826.0},
{'pequity': 0.473987425, 'total': 44789781494.0},
{'pequity': 0.470739815, 'total': 222499000000.0},
{'pequity': 0.469682435, 'total': 72718319931.0},
{'pequity': 0.460955268, 'total': 52888450676.0},
{'pequity': 0.454973874, 'total': 90023055250.0},
{'pequity': 0.44679832, 'total': 4754240139.0},
{'pequity': 0.445399024, 'total': 1860137274.0},
{'pequity': 0.445084958, 'total': 50012066209.0},
{'pequity': 0.434558735, 'total': 49289017295.0},
{'pequity': 0.428538866, 'total': 41569179291.0},
{'pequity': 0.41951359, 'total': 7018167989.0},
{'pequity': 0.396038585, 'total': 18903076296.0},
{'pequity': 0.385996777, 'total': 94845890023.0},
{'pequity': 0.3812259, 'total': 98841184094.0},
{'pequity': 0.371094794, 'total': 1431333898.0},
{'pequity': 0.365174764, 'total': 257971000000.0},
{'pequity': 0.35268716, 'total': 20795433552.0},
{'pequity': 0.351769714, 'total': 46931277851.0},
{'pequity': 0.345540928, 'total': 100671761.5},
{'pequity': 0.345042619, 'total': 255962000000.0},
{'pequity': 0.314932486, 'total': 5787699612.0},
{'pequity': 0.309844838, 'total': 3188814099.0},
{'pequity': 0.302505711, 'total': 369297000000.0},
{'pequity': 0.300290501, 'total': 61328595371.0},
{'pequity': 0.295468038, 'total': 20050870773.0},
{'pequity': 0.288731133, 'total': 28168716566.0},
{'pequity': 0.28162825, 'total': 64373673559.0},
{'pequity': 0.276328709, 'total': 16485758359.0},
{'pequity': 0.272881943, 'total': 16147599057.0},
{'pequity': 0.271453039, 'total': 2928943682.0},
{'pequity': 0.266499192, 'total': 21680176766.0},
{'pequity': 0.263242046, 'total': 26901134796.0},
{'pequity': 0.256506237, 'total': 27264058954.0},
{'pequity': 0.24385484, 'total': 11826556257.0},
{'pequity': 0.212618709, 'total': 142548000000.0},
{'pequity': 0.206427, 'total': 987906653.4},
{'pequity': 0.180456114, 'total': 23091916753.0},
{'pequity': 0.1795785, 'total': 11992158423.0},
{'pequity': 0.179430445, 'total': 3487165569.0},
{'pequity': 0.178686517, 'total': 6136684295.0},
{'pequity': 0.165903599, 'total': 3174960123.0},
{'pequity': 0.157774552, 'total': 1102371297.0},
{'pequity': 0.154730021, 'total': 152300000000.0},
{'pequity': 0.153370048, 'total': 277961000000.0},
{'pequity': 0.150154936, 'total': 9120805049.0},
{'pequity': 0.138031161, 'total': 13585651275.0},
{'pequity': 0.132149555, 'total': 5866131520.0},
{'pequity': 0.127044391, 'total': 107968000000.0},
{'pequity': 0.118377486, 'total': 192425000000.0},
{'pequity': 0.112239901, 'total': 21685959074.0},
{'pequity': 0.10993787, 'total': 138104000000.0},
{'pequity': 0.102825314, 'total': 664998672.3},
{'pequity': 0.100750551, 'total': 5070893025.0},
{'pequity': 0.098320627, 'total': 11934005108.0},
{'pequity': 0.085851591, 'total': 95949611145.0},
{'pequity': 0.084841651, 'total': 130194000000.0},
{'pequity': 0.075753702, 'total': 4242368665.0},
{'pequity': 0.070840029, 'total': 65237058794.0},
{'pequity': 0.069366366, 'total': 8924237004.0},
{'pequity': 0.065697627, 'total': 125058000000.0},
{'pequity': 0.062568593, 'total': 30980215635.0},
{'pequity': 0.045230625, 'total': 15276099395.0},
{'pequity': 0.044570177, 'total': 3394981597.0},
{'pequity': 0.033796831, 'total': 458403426.1},
{'pequity': 0.032226083, 'total': 1479573059.0},
{'pequity': 0.026393495, 'total': 2219070269.0},
{'pequity': 0.025384872, 'total': 27453319886.0},
{'pequity': 0.023300471, 'total': 38244344058.0},
{'pequity': 0.023052145, 'total': 32731585574.0},
{'pequity': 0.022364885, 'total': 85876344739.0},
{'pequity': 0.01707023, 'total': 99129084307.0},
{'pequity': 0.016398224, 'total': 32021523348.0},
{'pequity': 0.012356364, 'total': 29362367552.0},
{'pequity': 0.005433651, 'total': 7857569806.0},
{'pequity': 0.00248832, 'total': 11804897194.0},
{'pequity': 0.001381446, 'total': 2959158279.0},
{'pequity': 0.0, 'total': 1260997046.0}];
var xScale = d3.scaleLinear()
.range([0,width])
.domain([0,1]);
var rScale = d3.scaleLinear()
.range([5,50])
.domain([0,500000000000]);
data.forEach(function (d,i) {
d.x = xScale(d.pequity);
d.y = 100;
});
var simulation = d3.forceSimulation(data)
.force("x", d3.forceX(function(d) {
return xScale(d.pequity);
}).strength(0.01))
.force("y", d3.forceY(function(d) {
return 100;
}).strength(0.01))
.force("collide", d3.forceCollide(10).iterations(1))
.stop();
for (var i = 0; i < 75; ++i) {
simulation.tick();
}
var circles = graphGroup.selectAll(null)
.data(data)
.enter()
.append("circle")
.attr("r", function(d) {return rScale(d.total)})
.attr("cx", function(d) { return d.x;})
.attr("cy", function(d) { return d.y;})
.style('fill', function(d) {return "#003366"; });
//})
<script src="https://d3js.org/d3.v5.min.js"></script>
I have had modest success by setting the strength
to a low value and forceCollide
to a high value:
var simulation = d3.forceSimulation(data)
.force("x", d3.forceX(function(d) {
return xScale(d.pequity);
}).strength(0.01))
.force("y", d3.forceY(function(d) {
return 100;
}).strength(0.01))
.force("collide", d3.forceCollide(10).iterations(1))
.stop();
However there are many instances where the circles are all lumped together.
My intended goal is to have each circle stand apart (not overlapping), but at the same time I want the circles to be placed closed together. I imagine this would entail variable force settings, not sure how small circles next to big circles should be handled (and vice versa).
Also, when I tried:
.force('collide', function(d) {return d3.forceCollide(rScale(d.total)).iterations(1)})
It reverted to an iteration that resembled a high force setting (all circles snapped to the center line). It seems that .force('collide',
does not support dynamic attribute. Though, I could be mistaken.
How can I adjust my force logic to account for variable radius sizes in my swarm circles such that each circle is close but not engulfed by another circle?
Upvotes: 0
Views: 189
Reputation: 102174
As previously suggested you just need to pass the radius of each circle to d3.forceCollide
. In your case:
.force("collide", d3.forceCollide(d => rScale(d.total)))
Here is your code with that change:
var margins = {
top: 20,
bottom: 300,
left: 100,
right: 100
};
var height = 200;
var width = 900;
var totalWidth = width + margins.left + margins.right;
var totalHeight = height + margins.top + margins.bottom;
var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);
var graphGroup = svg.append('g')
.attr('transform', "translate(" + margins.left + "," + margins.top + ")");
//var tsvData = d3.tsv('fmc-equity.tsv');
//tsvData.then(function(rawData) {
//var data = rawData.map(function(d) {
//return {fmc:d.fmc, pequity:+d.pequity, total:+d.total, rank:+d.rank}
//});
var data = [{
'pequity': 1.0,
'total': 24902636438.0
},
{
'pequity': 1.0,
'total': 8204868902.0
},
{
'pequity': 1.0,
'total': 6658546024.0
},
{
'pequity': 1.0,
'total': 6126023357.0
},
{
'pequity': 1.0,
'total': 2193415702.0
},
{
'pequity': 1.0,
'total': 1734784625.0
},
{
'pequity': 1.0,
'total': 1296048848.0
},
{
'pequity': 1.0,
'total': 308649243.8
},
{
'pequity': 1.0,
'total': 295207349.3
},
{
'pequity': 1.0,
'total': 234857862.9
},
{
'pequity': 1.0,
'total': 156598861.9
},
{
'pequity': 1.0,
'total': 104983353.0
},
{
'pequity': 1.0,
'total': 63690617.76
},
{
'pequity': 1.0,
'total': 59401648.51
},
{
'pequity': 0.975623135,
'total': 14007871265.0
},
{
'pequity': 0.967237964,
'total': 1685804854.0
},
{
'pequity': 0.963917349,
'total': 293309822.9
},
{
'pequity': 0.934185443,
'total': 2917969779.0
},
{
'pequity': 0.933316698,
'total': 30102340057.0
},
{
'pequity': 0.915294851,
'total': 24722091961.0
},
{
'pequity': 0.913848269,
'total': 25585870482.0
},
{
'pequity': 0.913408996,
'total': 2991804061.0
},
{
'pequity': 0.892768552,
'total': 9977890414.0
},
{
'pequity': 0.845989331,
'total': 88124798828.0
},
{
'pequity': 0.829158756,
'total': 1180176138.0
},
{
'pequity': 0.827893585,
'total': 21493562671.0
},
{
'pequity': 0.815844492,
'total': 1141920435.0
},
{
'pequity': 0.793349904,
'total': 45529532260.0
},
{
'pequity': 0.784721035,
'total': 163020000000.0
},
{
'pequity': 0.778621751,
'total': 2758477982.0
},
{
'pequity': 0.776066588,
'total': 96073251741.0
},
{
'pequity': 0.752238939,
'total': 34388436875.0
},
{
'pequity': 0.742142911,
'total': 1406030271.0
},
{
'pequity': 0.740334287,
'total': 4711578569.0
},
{
'pequity': 0.738044554,
'total': 72969280487.0
},
{
'pequity': 0.728912674,
'total': 51810952821.0
},
{
'pequity': 0.723159895,
'total': 147101000000.0
},
{
'pequity': 0.717957188,
'total': 380923000000.0
},
{
'pequity': 0.702860894,
'total': 1971690322.0
},
{
'pequity': 0.700934687,
'total': 334084000000.0
},
{
'pequity': 0.684489847,
'total': 162390000000.0
},
{
'pequity': 0.679992279,
'total': 57956445277.0
},
{
'pequity': 0.669998233,
'total': 3758791332.0
},
{
'pequity': 0.667230968,
'total': 187355000000.0
},
{
'pequity': 0.653736462,
'total': 186999000000.0
},
{
'pequity': 0.650328323,
'total': 76326103402.0
},
{
'pequity': 0.642256236,
'total': 244641000000.0
},
{
'pequity': 0.642232384,
'total': 21058144224.0
},
{
'pequity': 0.634697091,
'total': 36845417753.0
},
{
'pequity': 0.625246046,
'total': 7505300217.0
},
{
'pequity': 0.622668225,
'total': 287937000000.0
},
{
'pequity': 0.615894348,
'total': 390042000000.0
},
{
'pequity': 0.614523365,
'total': 493581000000.0
},
{
'pequity': 0.610259063,
'total': 187658000000.0
},
{
'pequity': 0.606075625,
'total': 20568282534.0
},
{
'pequity': 0.566893948,
'total': 13561590623.0
},
{
'pequity': 0.562164622,
'total': 1752893048.0
},
{
'pequity': 0.548193052,
'total': 54080529801.0
},
{
'pequity': 0.547672307,
'total': 333058000000.0
},
{
'pequity': 0.503813337,
'total': 61882066527.0
},
{
'pequity': 0.499762105,
'total': 549015425.1
},
{
'pequity': 0.492513345,
'total': 1922398097.0
},
{
'pequity': 0.482375439,
'total': 174165000000.0
},
{
'pequity': 0.481469613,
'total': 23194895826.0
},
{
'pequity': 0.473987425,
'total': 44789781494.0
},
{
'pequity': 0.470739815,
'total': 222499000000.0
},
{
'pequity': 0.469682435,
'total': 72718319931.0
},
{
'pequity': 0.460955268,
'total': 52888450676.0
},
{
'pequity': 0.454973874,
'total': 90023055250.0
},
{
'pequity': 0.44679832,
'total': 4754240139.0
},
{
'pequity': 0.445399024,
'total': 1860137274.0
},
{
'pequity': 0.445084958,
'total': 50012066209.0
},
{
'pequity': 0.434558735,
'total': 49289017295.0
},
{
'pequity': 0.428538866,
'total': 41569179291.0
},
{
'pequity': 0.41951359,
'total': 7018167989.0
},
{
'pequity': 0.396038585,
'total': 18903076296.0
},
{
'pequity': 0.385996777,
'total': 94845890023.0
},
{
'pequity': 0.3812259,
'total': 98841184094.0
},
{
'pequity': 0.371094794,
'total': 1431333898.0
},
{
'pequity': 0.365174764,
'total': 257971000000.0
},
{
'pequity': 0.35268716,
'total': 20795433552.0
},
{
'pequity': 0.351769714,
'total': 46931277851.0
},
{
'pequity': 0.345540928,
'total': 100671761.5
},
{
'pequity': 0.345042619,
'total': 255962000000.0
},
{
'pequity': 0.314932486,
'total': 5787699612.0
},
{
'pequity': 0.309844838,
'total': 3188814099.0
},
{
'pequity': 0.302505711,
'total': 369297000000.0
},
{
'pequity': 0.300290501,
'total': 61328595371.0
},
{
'pequity': 0.295468038,
'total': 20050870773.0
},
{
'pequity': 0.288731133,
'total': 28168716566.0
},
{
'pequity': 0.28162825,
'total': 64373673559.0
},
{
'pequity': 0.276328709,
'total': 16485758359.0
},
{
'pequity': 0.272881943,
'total': 16147599057.0
},
{
'pequity': 0.271453039,
'total': 2928943682.0
},
{
'pequity': 0.266499192,
'total': 21680176766.0
},
{
'pequity': 0.263242046,
'total': 26901134796.0
},
{
'pequity': 0.256506237,
'total': 27264058954.0
},
{
'pequity': 0.24385484,
'total': 11826556257.0
},
{
'pequity': 0.212618709,
'total': 142548000000.0
},
{
'pequity': 0.206427,
'total': 987906653.4
},
{
'pequity': 0.180456114,
'total': 23091916753.0
},
{
'pequity': 0.1795785,
'total': 11992158423.0
},
{
'pequity': 0.179430445,
'total': 3487165569.0
},
{
'pequity': 0.178686517,
'total': 6136684295.0
},
{
'pequity': 0.165903599,
'total': 3174960123.0
},
{
'pequity': 0.157774552,
'total': 1102371297.0
},
{
'pequity': 0.154730021,
'total': 152300000000.0
},
{
'pequity': 0.153370048,
'total': 277961000000.0
},
{
'pequity': 0.150154936,
'total': 9120805049.0
},
{
'pequity': 0.138031161,
'total': 13585651275.0
},
{
'pequity': 0.132149555,
'total': 5866131520.0
},
{
'pequity': 0.127044391,
'total': 107968000000.0
},
{
'pequity': 0.118377486,
'total': 192425000000.0
},
{
'pequity': 0.112239901,
'total': 21685959074.0
},
{
'pequity': 0.10993787,
'total': 138104000000.0
},
{
'pequity': 0.102825314,
'total': 664998672.3
},
{
'pequity': 0.100750551,
'total': 5070893025.0
},
{
'pequity': 0.098320627,
'total': 11934005108.0
},
{
'pequity': 0.085851591,
'total': 95949611145.0
},
{
'pequity': 0.084841651,
'total': 130194000000.0
},
{
'pequity': 0.075753702,
'total': 4242368665.0
},
{
'pequity': 0.070840029,
'total': 65237058794.0
},
{
'pequity': 0.069366366,
'total': 8924237004.0
},
{
'pequity': 0.065697627,
'total': 125058000000.0
},
{
'pequity': 0.062568593,
'total': 30980215635.0
},
{
'pequity': 0.045230625,
'total': 15276099395.0
},
{
'pequity': 0.044570177,
'total': 3394981597.0
},
{
'pequity': 0.033796831,
'total': 458403426.1
},
{
'pequity': 0.032226083,
'total': 1479573059.0
},
{
'pequity': 0.026393495,
'total': 2219070269.0
},
{
'pequity': 0.025384872,
'total': 27453319886.0
},
{
'pequity': 0.023300471,
'total': 38244344058.0
},
{
'pequity': 0.023052145,
'total': 32731585574.0
},
{
'pequity': 0.022364885,
'total': 85876344739.0
},
{
'pequity': 0.01707023,
'total': 99129084307.0
},
{
'pequity': 0.016398224,
'total': 32021523348.0
},
{
'pequity': 0.012356364,
'total': 29362367552.0
},
{
'pequity': 0.005433651,
'total': 7857569806.0
},
{
'pequity': 0.00248832,
'total': 11804897194.0
},
{
'pequity': 0.001381446,
'total': 2959158279.0
},
{
'pequity': 0.0,
'total': 1260997046.0
}
];
var xScale = d3.scaleLinear()
.range([0, width])
.domain([0, 1]);
var rScale = d3.scaleLinear()
.range([5, 50])
.domain([0, 500000000000]);
data.forEach(function(d, i) {
d.x = xScale(d.pequity);
d.y = 100;
});
var simulation = d3.forceSimulation(data)
.force("x", d3.forceX(function(d) {
return xScale(d.pequity);
}).strength(0.01))
.force("y", d3.forceY(function(d) {
return 100;
}).strength(0.01))
.force("collide", d3.forceCollide(d => rScale(d.total)))
.stop();
simulation.tick(75);
var circles = graphGroup.selectAll(null)
.data(data)
.enter()
.append("circle")
.attr("r", function(d) {
return rScale(d.total)
})
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
});
//})
circle {
fill: tan;
stroke: black;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
Some observations:
In D3 v5, this...
for (var i = 0; i < 75; ++i) {
simulation.tick();
}
can be just:
simulation.tick(75);
You are encoding a value as the circle area, not the circle radius. As such, I strongly suggest that you use a square root scale instead of a linear scale.
Upvotes: 1