#javascript #sorting #svg #d3.js #circle-pack
#javascript #сортировка #svg #d3.js #круг-пакет
Вопрос:
Итак, я использую тот же код, что и в этом примере галереи D3 (с моими собственными данными):
Я хотел бы получить пузырьковую диаграмму, в которой круги расположены с наибольшим в центре, а затем расходятся до наименьшего.
Вот макет, который я создал в Photoshop:
Вот что я получаю, когда использую пример (алгоритм упаковки круга по умолчанию с сортировкой по умолчанию):
Я попытался настроить сортировку (включая попытку d3.ascending и d3.descending). Лучшее, что я мог придумать, просто в основном подрывает сортировку с константой (ха!), Но все еще далеко от того, что я хотел бы:
//...
.sort( function(a, b) { return -1;} )
//...
Хорошо, есть ли шанс, что это можно сделать без необходимости изменять фактический алгоритм компоновки пакета D3? Если нет, возможно, кто-то расширил или изменил макет пакета и мог бы подсказать мне 5 строк, которые я мог бы изменить в исходном коде D3, чтобы взломать это.
Заранее спасибо!
Редактировать:
Как и было запрошено, вот код, который я использую. В основном то же самое, что и в приведенном выше примере, с несколькими поверхностными изменениями, как указано в комментариях:
var diameter = 960,
format = d3.format(",d"),
color = d3.scale.category20c();
var bubble = d3.layout.pack()
// .sort(null)
// .sort(d3.ascending)
// .sort(d3.descending)
.sort( function(a, b) { return -1;} ) // basically a < b always
.size([diameter, diameter])
.padding(1.5);
var svg = d3.select("body").append("svg")
.attr("width", diameter)
.attr("height", diameter)
.attr("class", "bubble");
d3.json("data.json", function(error, root)
{
var node = svg.selectAll(".node")
.data(bubble.nodes(classes(root))
.filter(function(d) { return !d.children; }))
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" d.x "," d.y ")"; });
node.append("title")
.text(function(d) { return d.className ": " format(d.value); });
node.append("circle")
.attr("r", function(d) { return d.r; })
.style("fill", function(d)
{
// return color(d.packageName);
return color(d.value); // this gives a different color for every leaf node
});
node.append("text")
.attr("dy", ".3em")
.style("text-anchor", "middle")
// .text(function(d) { return d.className.substring(0, d.r / 3); });
});
// Returns a flattened hierarchy containing all leaf nodes under the root.
function classes(root)
{
var classes = [];
function recurse(name, node) {
if (node.children) node.children.forEach(function(child) { recurse(node.name, child); });
else classes.push({packageName: name, className: node.name, value: node.size});
}
recurse(null, root);
return {children: classes};
}
d3.select(self.frameElement).style("height", diameter "px");
И мой файл data.json:
{
"name": "Root",
"children": [
{
"name": "Leaf",
"children": null,
"size": 2098629
},
{
"name": "Leaf",
"children": null,
"size": 104720
},
{
"name": "Leaf",
"children": null,
"size": 5430
},
{
"name": "Leaf",
"children": null,
"size": 102096
},
{
"name": "Leaf",
"children": null,
"size": 986974
},
{
"name": "Leaf",
"children": null,
"size": 59735
},
{
"name": "Leaf",
"children": null,
"size": 1902
},
{
"name": "Leaf",
"children": null,
"size": 120
},
{
"name": "Leaf",
"children": null,
"size": 870751
},
{
"name": "Leaf",
"children": null,
"size": 36672
},
{
"name": "Leaf",
"children": null,
"size": 274338
},
{
"name": "Leaf",
"children": null,
"size": 517693
},
{
"name": "Leaf",
"children": null,
"size": 145807
},
{
"name": "Leaf",
"children": null,
"size": 476178
},
{
"name": "Leaf",
"children": null,
"size": 11771
},
{
"name": "Leaf",
"children": null,
"size": 153
},
{
"name": "Leaf",
"children": null,
"size": 2138
},
{
"name": "Leaf",
"children": null,
"size": 8436
},
{
"name": "Leaf",
"children": null,
"size": 3572
},
{
"name": "Leaf",
"children": null,
"size": 120235
},
{
"name": "Leaf",
"children": null,
"size": 210945
},
{
"name": "Leaf",
"children": null,
"size": 56033
},
{
"name": "Leaf",
"children": null,
"size": 358704
},
{
"name": "Leaf",
"children": null,
"size": 295736
},
{
"name": "Leaf",
"children": null,
"size": 26087
},
{
"name": "Leaf",
"children": null,
"size": 33110
},
{
"name": "Leaf",
"children": null,
"size": 3828
},
{
"name": "Leaf",
"children": null,
"size": 1105544
},
{
"name": "Leaf",
"children": null,
"size": 98740
},
{
"name": "Leaf",
"children": null,
"size": 80723
},
{
"name": "Leaf",
"children": null,
"size": 5766
},
{
"name": "Leaf",
"children": null,
"size": 1453
},
{
"name": "Leaf",
"children": null,
"size": 10443176
},
{
"name": "Leaf",
"children": null,
"size": 14055
},
{
"name": "Leaf",
"children": null,
"size": 1890127
},
{
"name": "Leaf",
"children": null,
"size": 404575
},
{
"name": "Leaf",
"children": null,
"size": 272777
},
{
"name": "Leaf",
"children": null,
"size": 1269763
},
{
"name": "Leaf",
"children": null,
"size": 5081
},
{
"name": "Leaf",
"children": null,
"size": 3168510
},
{
"name": "Leaf",
"children": null,
"size": 717031
},
{
"name": "Leaf",
"children": null,
"size": 88418
},
{
"name": "Leaf",
"children": null,
"size": 762084
},
{
"name": "Leaf",
"children": null,
"size": 255055
},
{
"name": "Leaf",
"children": null,
"size": 535
},
{
"name": "Leaf",
"children": null,
"size": 81238
},
{
"name": "Leaf",
"children": null,
"size": 17075
},
{
"name": "Leaf",
"children": null,
"size": 5331
},
{
"name": "Leaf",
"children": null,
"size": 74834
},
{
"name": "Leaf",
"children": null,
"size": 110359
},
{
"name": "Leaf",
"children": null,
"size": 27333
},
{
"name": "Leaf",
"children": null,
"size": 143
},
{
"name": "Leaf",
"children": null,
"size": 12721
},
{
"name": "Leaf",
"children": null,
"size": 529
},
{
"name": "Leaf",
"children": null,
"size": 115684
},
{
"name": "Leaf",
"children": null,
"size": 3990850
},
{
"name": "Leaf",
"children": null,
"size": 6045060
},
{
"name": "Leaf",
"children": null,
"size": 2445766
},
{
"name": "Leaf",
"children": null,
"size": 479865
},
{
"name": "Leaf",
"children": null,
"size": 105743
},
{
"name": "Leaf",
"children": null,
"size": 183750
},
{
"name": "Leaf",
"children": null,
"size": 661
},
{
"name": "Leaf",
"children": null,
"size": 11181
}
],
"size": 41103329
}
Комментарии:
1. Для этого вам понадобится пользовательский макет — макет пакета всегда будет упаковывать маленькие круги между большими кругами, поскольку это уменьшает потерянное пространство. О, и нет необходимости выделять все жирным шрифтом.
2. Конечно, имеет смысл, просто надеясь, что кто-то столкнулся с достаточно похожим вариантом использования и уже нашел решение. Да, не нужно выделять все жирным шрифтом; в основном это была ошибка с вырезанием и вставкой. Теперь выделены жирным шрифтом только заголовки изображений 🙂
3. @SoldierOfFortran, ты можешь просто прикрепить данные из своего примера? Код (по крайней мере, ключевые части) также желателен.
4. @VividD — Готово. Надеюсь, это поможет.
Ответ №1:
Все, что вам нужно сделать, это указать:
.sort(function(a, b) {
return -(a.value - b.value);
})
Это отличается от указания .sort(d3.ascending)
или .sort(d3.descending)
, поскольку d3.ascending
и d3.descending
определяются как
function(a, b) {
return a < b ? -1 : a > b ? 1 : 0;
}
и
function(a, b) {
return b < a ? -1 : b > a ? 1 : 0;
}
соответственно, и на макет пакета влияет их «нечувствительность» к разнице точек данных.
Это мой тестовый пример: (с вашими данными) jsfiddle
В качестве эксперимента я также применил следующую функцию сортировки: (это своего рода гибрид)
.sort( function(a, b) {
var threshold = 10000000;
if ((a.value > threshold) amp;amp; (b.value > threshold)) {
return -(a.value - b.value);
} else {
return -1;
}
})
… и для значений для порога 10000000, 3000000, 1000000, 300000, 100000, 30000 соответственно, я получил: jsfiddle
Комментарии:
1. Привет @VividD ! возможно ли получить разрыв между этими пузырьками?