d3.hierarchy в целом и d3.partition в частности являются одними из моих любимых инструментов из этой великой библиотеки.Но я впервые применяю их к радиальным «солнечным лучам», а именно, кажется, отсутствуют некоторые важные биты.
Ниже приведен пример MCVE , генерирующий эти солнечные лучи, чтобы проиллюстрироватьмои основные вопросы: ![sample sunburst](https://i.stack.imgur.com/jmAW6.png)
Поворот текста
Поворот текстовых меток за пределы 180 градусов является распространенной проблемой;ср это недавнее сообщение SO
После @ собственного примера mbostock имеет этот код преобразования:
.attr("transform", function(d) {
const x = (d.x0 + d.x1) / 2 * 180 / Math.PI;
const y = (d.y0 + d.y1) / 2;
return `rotate(${x - 90}) translate(${y},0) rotate(${x < 180 ? 0 : 180})`;
})
, но с использованием этого translate()
в преобразованииотбрасывает текст далеко от графика?
Таким образом, приведенный ниже код выполняет вращение на основе одного и того же среднего радиуса внутренней / внешней дуги и размещает метки справа (углы <180) таким же образом, за исключениемчто он использует <code>text-anchor вариант выравнивания, чтобы выровнять метки обеих глубин по одному и тому же общему кругу.
1 Мне пришлось изменить радиус взломанным фактором 1.22
чтобы подтолкнуть (правую) метки близко к линии; почему ?
2 Это прекрасно работает для всех меток, кроме корневых, которые я хочу центрировать; как я могу это сделать?
3 Но новые левые (> 180 градусов) метки расположены неправильно, и мне нужно было добавитьспецифичная для глубины hackRatio
, чтобы смягчить перевод, чтобы даже приблизить их; почему?
4 Более серьезная проблема состоит в том, чтобы выяснить, как использовать тот же прием text-anchor
выравнивания, используемый для других меток?Я хочу сделать вращение «на месте» до применения выравнивания ; как я могу это сделать?
Как должна работать d3.hierarchy.sum ()?
Надписи также включают freq
атрибут в скобках.Данные yearHier
предоставляют этот атрибут только для данных листья .Из d3.hierarchy.sum () и d3.partition doc у меня сложилось впечатление, что при вызове корня sum()
в корне будут вычисляться суммы для не-листьев ("... для этого узла и каждого потомка в обходе после заказа "); почему эти частоты равны нулю?
Итак, в качестве альтернативы я попытался использовать данные yearHierFreq
, которые включают общие частоты для корня и каждого года.Но используя его, d3.partition выделяет только две трети дуг лет и только половину дуг месяцев в каждом году;см. рендеринг ниже.Это как если бы внутренние узлы 'freq
были подсчитаны дважды; почему ?
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
var ColorNames = ["Blue", "Gray", "Purple", "Fuchsia", "Aqua", "Maroon", "Olive", "Yellow", "Teal", "Navy", "Green", "Silver", "Red", "Lime"];
// following after http://bl.ocks.org/kerryrodden/7090426
var width = 900;
var height = 900;
var radius = Math.min(width, height) / 2 * 0.7;
var vis = d3.select("#chart").append("svg:svg")
.attr("width", width)
.attr("height", height)
.append("svg:g")
.attr("id", "container")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var partition = d3.partition()
.size([2 * Math.PI, radius * radius]);
var arc = d3.arc()
.startAngle(function(d) { return d.x0; })
.endAngle(function(d) { return d.x1; })
.innerRadius(function(d) { return Math.sqrt(d.y0); })
.outerRadius(function(d) { return Math.sqrt(d.y1); });
function createSunburst(json) {
vis.append("svg:circle")
.attr("r", radius)
.style("opacity", 0);
// Turn the data into a d3 hierarchy and calculate the sums.
var root = d3.hierarchy(json)
.sum(function(d) { return d.freq; })
.sort(function(a, b) { return b.name - a.name; });
var partition = d3.partition()
.size([2 * Math.PI, radius * radius]);
var nodes = partition(root).descendants();
var path = vis.data([json]).selectAll("path")
.data(nodes)
.enter().append("svg:path")
.attr("display", function(d) { return d.depth ? null : "none"; })
.attr("d", arc)
.attr("fill-rule", "evenodd")
.style("fill", function(d,i) { return ColorNames[i % 14]; })
.style("opacity", 1);
var texts = vis.selectAll("text")
.data(nodes)
.enter().append("text")
/* .attr("transform", function(d) {
// https://beta.observablehq.com/@mbostock/d3-sunburst
const x = (d.x0 + d.x1) / 2 * 180 / Math.PI;
const y = (d.y0 + d.y1) / 2;
return `rotate(${x - 90}) translate(${y},0) rotate(${x < 180 ? 0 : 180})`;
})
*/
.attr("transform", function(d) {
var deg;
if (d.depth==0) {
deg = 90;
} else {
deg = 180 / Math.PI * (d.x0 +d.x1) / 2;
}
var trans = `rotate(${deg-90})`;
if (deg > 180) {
var hackRatio = (d.depth == 0) ? 160 : 130;
var yavg = (d.y0 + d.y1) / 2 / hackRatio;
trans += ` translate(${yavg},0) rotate(180)`;
}
return trans})
.attr("x", radius / 1.22 )
.text(function(d) {return `${d.data.name} (${d.data.freq})`;})
.attr("text-anchor", function(d) {
var alignVec = ["center","end","start"];
return alignVec[d.depth];})
};
var yearHier = {"freq": 0, "name": "AllYears", "children": [{"freq": 0, "name": "2017", "children": [{"freq": 5, "name": "January", "children": []}, {"freq": 17, "name": "February", "children": []}, {"freq": 16, "name": "March", "children": []}, {"freq": 2, "name": "April", "children": []}, {"freq": 18, "name": "May", "children": []}, {"freq": 14, "name": "June", "children": []}, {"freq": 17, "name": "July", "children": []}, {"freq": 2, "name": "August", "children": []}, {"freq": 10, "name": "September", "children": []}, {"freq": 6, "name": "October", "children": []}, {"freq": 10, "name": "November", "children": []}, {"freq": 17, "name": "December", "children": []}]}, {"freq": 0, "name": "2018", "children": [{"freq": 14, "name": "January", "children": []}, {"freq": 6, "name": "February", "children": []}, {"freq": 13, "name": "March", "children": []}, {"freq": 15, "name": "April", "children": []}, {"freq": 15, "name": "May", "children": []}, {"freq": 4, "name": "June", "children": []}, {"freq": 7, "name": "July", "children": []}, {"freq": 12, "name": "August", "children": []}, {"freq": 17, "name": "September", "children": []}, {"freq": 8, "name": "October", "children": []}, {"freq": 10, "name": "November", "children": []}, {"freq": 12, "name": "December", "children": []}]}, {"freq": 0, "name": "2019", "children": [{"freq": 10, "name": "January", "children": []}, {"freq": 12, "name": "February", "children": []}, {"freq": 15, "name": "March", "children": []}, {"freq": 6, "name": "April", "children": []}, {"freq": 14, "name": "May", "children": []}, {"freq": 3, "name": "June", "children": []}, {"freq": 6, "name": "July", "children": []}, {"freq": 9, "name": "August", "children": []}, {"freq": 18, "name": "September", "children": []}, {"freq": 4, "name": "October", "children": []}, {"freq": 8, "name": "November", "children": []}, {"freq": 16, "name": "December", "children": []}]}]}
var yearHierFreq = {"freq": 355, "name": "AllMonths", "children": [{"freq": 83, "name": "2017", "children": [{"freq": 4, "name": "January", "children": []}, {"freq": 7, "name": "February", "children": []}, {"freq": 4, "name": "March", "children": []}, {"freq": 11, "name": "April", "children": []}, {"freq": 16, "name": "May", "children": []}, {"freq": 8, "name": "June", "children": []}, {"freq": 5, "name": "July", "children": []}, {"freq": 3, "name": "August", "children": []}, {"freq": 10, "name": "September", "children": []}, {"freq": 3, "name": "October", "children": []}, {"freq": 2, "name": "November", "children": []}, {"freq": 10, "name": "December", "children": []}]}, {"freq": 156, "name": "2018", "children": [{"freq": 14, "name": "January", "children": []}, {"freq": 8, "name": "February", "children": []}, {"freq": 12, "name": "March", "children": []}, {"freq": 10, "name": "April", "children": []}, {"freq": 16, "name": "May", "children": []}, {"freq": 17, "name": "June", "children": []}, {"freq": 19, "name": "July", "children": []}, {"freq": 14, "name": "August", "children": []}, {"freq": 4, "name": "September", "children": []}, {"freq": 17, "name": "October", "children": []}, {"freq": 19, "name": "November", "children": []}, {"freq": 6, "name": "December", "children": []}]}, {"freq": 116, "name": "2019", "children": [{"freq": 4, "name": "January", "children": []}, {"freq": 15, "name": "February", "children": []}, {"freq": 12, "name": "March", "children": []}, {"freq": 8, "name": "April", "children": []}, {"freq": 3, "name": "May", "children": []}, {"freq": 5, "name": "June", "children": []}, {"freq": 13, "name": "July", "children": []}, {"freq": 19, "name": "August", "children": []}, {"freq": 12, "name": "September", "children": []}, {"freq": 11, "name": "October", "children": []}, {"freq": 5, "name": "November", "children": []}, {"freq": 9, "name": "December", "children": []}]}]}
createSunburst(yearHier);
d3.select(self.frameElement).style("height", "700px");
</script>