[英]How to add colours to D3 js sunburst diagram from JSON-file?
I created a sunburst diagram based on this JSON file.我根据这个JSON 文件创建了一个旭日形图。 (existing quetions considered)
(考虑现有问题)
The first few lines look like this:前几行如下所示:
{
"name": "A", "children": [
{
"name": "B",
"color": "#A9DFBF",
"children": [
{
"name": "C",
"color": "#F9E79F",
"children": [
....
....
....
I am trying to use the colours from the JSON file in the sunburst: in this example everything has to be green besides one yellow arc.我正在尝试使用 sunburst 中 JSON 文件中的颜色:在这个例子中,除了一个黄色弧线之外,所有东西都必须是绿色的。 Instead my code (s. below) gives me the following sunburst visualizations with the two alternatives I tried:
相反,我的代码(如下)为我提供了以下旭日形可视化效果,其中包含我尝试过的两种替代方案:
Alternative 1 of the relvant part gives:相关部分的备选方案 1 给出:
Alternative 2 of the relevant part (search for "alternative") gives:
相关部分的备选方案 2(搜索“备选方案”)给出:
Would appriciate any help on this.会为此提供任何帮助。
Relevant part of code:代码的相关部分:
newSlice.append('path')
.attr('class', 'main-arc')
//Alternative 1
//.style('fill', d => color((d.children ? d : d.parent).data.name))
//Alternative 2
.style('fill', function (d) { return color(d.color);})
.attr('d', arc);
Full code:完整代码:
<head>
<style>
body {
font-family: Sans-serif;
font-size: 11px;
}
.slice {
cursor: pointer;
}
.slice .main-arc {
stroke: #fff;
stroke-width: 1px;
}
.slice .hidden-arc {
fill: none;
}
.slice text {
pointer-events: none;
dominant-baseline: middle;
text-anchor: middle;
}
</style>
<script src='https://d3js.org/d3.v4.min.js'></script>
</head>
<body>
<script>
const width = window.innerWidth,
height = window.innerHeight,
maxRadius = (Math.min(width, height) / 2) - 5;
const formatNumber = d3.format(',d');
const x = d3.scaleLinear()
.range([0, 2 * Math.PI])
.clamp(true);
const y = d3.scaleSqrt()
.range([maxRadius*.1, maxRadius]);
const color = d3.scaleOrdinal(d3.schemeCategory20);
const partition = d3.partition();
const arc = d3.arc()
.startAngle(d => x(d.x0))
.endAngle(d => x(d.x1))
.innerRadius(d => Math.max(0, y(d.y0)))
.outerRadius(d => Math.max(0, y(d.y1)));
const middleArcLine = d => {
const halfPi = Math.PI/2;
const angles = [x(d.x0) - halfPi, x(d.x1) - halfPi];
const r = Math.max(0, (y(d.y0) + y(d.y1)) / 2);
const middleAngle = (angles[1] + angles[0]) / 2;
const invertDirection = middleAngle > 0 && middleAngle < Math.PI; // On lower quadrants write text ccw
if (invertDirection) { angles.reverse(); }
const path = d3.path();
path.arc(0, 0, r, angles[0], angles[1], invertDirection);
return path.toString();
};
const textFits = d => {
const CHAR_SPACE = 6;
const deltaAngle = x(d.x1) - x(d.x0);
const r = Math.max(0, (y(d.y0) + y(d.y1)) / 2);
const perimeter = r * deltaAngle;
return d.data.name.length * CHAR_SPACE < perimeter;
};
const svg = d3.select('body').append('svg')
.style('width', '100vw')
.style('height', '100vh')
.attr('viewBox', `${-width / 2} ${-height / 2} ${width} ${height}`)
.on('click', () => focusOn()); // Reset zoom on canvas click
d3.json('https://raw.githubusercontent.com/graphineer/viz/master/flare-3.json', (error, root) => {
if (error) throw error;
root = d3.hierarchy(root);
root.sum(d => d.size);
const slice = svg.selectAll('g.slice')
.data(partition(root).descendants());
slice.exit().remove();
const newSlice = slice.enter()
.append('g').attr('class', 'slice')
.on('click', d => {
d3.event.stopPropagation();
focusOn(d);
});
newSlice.append('title')
.text(d => d.data.name + '\n' + formatNumber(d.value));
newSlice.append('path')
.attr('class', 'main-arc')
//Alternative 1
//.style('fill', d => color((d.children ? d : d.parent).data.name))
//Alternative 2
.style('fill', function (d) { return color(d.color);})
.attr('d', arc);
newSlice.append('path')
.attr('class', 'hidden-arc')
.attr('id', (_, i) => `hiddenArc${i}`)
.attr('d', middleArcLine);
const text = newSlice.append('text')
.attr('display', d => textFits(d) ? null : 'none');
// Add white contour
text.append('textPath')
.attr('startOffset','50%')
.attr('xlink:href', (_, i) => `#hiddenArc${i}` )
.text(d => d.data.name)
.style('fill', 'none')
.style('stroke', '#fff')
.style('stroke-width', 5)
.style('stroke-linejoin', 'round');
text.append('textPath')
.attr('startOffset','50%')
.attr('xlink:href', (_, i) => `#hiddenArc${i}` )
.text(d => d.data.name);
});
function focusOn(d = { x0: 0, x1: 1, y0: 0, y1: 1 }) {
// Reset to top-level if no data point specified
const transition = svg.transition()
.duration(750)
.tween('scale', () => {
const xd = d3.interpolate(x.domain(), [d.x0, d.x1]),
yd = d3.interpolate(y.domain(), [d.y0, 1]);
return t => { x.domain(xd(t)); y.domain(yd(t)); };
});
transition.selectAll('path.main-arc')
.attrTween('d', d => () => arc(d));
transition.selectAll('path.hidden-arc')
.attrTween('d', d => () => middleArcLine(d));
transition.selectAll('text')
.attrTween('display', d => () => textFits(d) ? null : 'none');
moveStackToFront(d);
//
function moveStackToFront(elD) {
svg.selectAll('.slice').filter(d => d === elD)
.each(function(d) {
this.parentNode.appendChild(this);
if (d.parent) { moveStackToFront(d.parent); }
})
}
}
</script>
</body>
Three observations:三个观察:
data
, created by the hierarchy generator;data
中;color
ordinal scale, since you already have the color hex value as the string;color
序数比例,因为您已经将颜色十六进制值作为字符串;color
property, therefore, assign a specific color to it ("red" in the example below, using logical OR).color
属性,因此,为它分配一个特定的颜色(在下面的示例中为“红色”,使用逻辑 OR)。 So, it is:所以,它是:
.style('fill', function(d) {
return d.data.color || "red"
})
Here is your code with that change only:这是您仅进行该更改的代码:
<head> <style> body { font-family: Sans-serif; font-size: 11px; }.slice { cursor: pointer; }.slice.main-arc { stroke: #fff; stroke-width: 1px; }.slice.hidden-arc { fill: none; }.slice text { pointer-events: none; dominant-baseline: middle; text-anchor: middle; } </style> <script src='https://d3js.org/d3.v4.min.js'></script> </head> <body> <script> const width = window.innerWidth, height = window.innerHeight, maxRadius = (Math.min(width, height) / 2) - 5; const formatNumber = d3.format(',d'); const x = d3.scaleLinear().range([0, 2 * Math.PI]).clamp(true); const y = d3.scaleSqrt().range([maxRadius *.1, maxRadius]); const color = d3.scaleOrdinal(d3.schemeCategory20); const partition = d3.partition(); const arc = d3.arc().startAngle(d => x(d.x0)).endAngle(d => x(d.x1)).innerRadius(d => Math.max(0, y(d.y0))).outerRadius(d => Math.max(0, y(d.y1))); const middleArcLine = d => { const halfPi = Math.PI / 2; const angles = [x(d.x0) - halfPi, x(d.x1) - halfPi]; const r = Math.max(0, (y(d.y0) + y(d.y1)) / 2); const middleAngle = (angles[1] + angles[0]) / 2; const invertDirection = middleAngle > 0 && middleAngle < Math.PI; // On lower quadrants write text ccw if (invertDirection) { angles.reverse(); } const path = d3.path(); path.arc(0, 0, r, angles[0], angles[1], invertDirection); return path.toString(); }; const textFits = d => { const CHAR_SPACE = 6; const deltaAngle = x(d.x1) - x(d.x0); const r = Math.max(0, (y(d.y0) + y(d.y1)) / 2); const perimeter = r * deltaAngle; return d.data.name.length * CHAR_SPACE < perimeter; }; const svg = d3.select('body').append('svg').style('width', '100vw').style('height', '100vh').attr('viewBox', `${-width / 2} ${-height / 2} ${width} ${height}`).on('click', () => focusOn()); // Reset zoom on canvas click d3.json('https://raw.githubusercontent.com/graphineer/viz/master/flare-3.json', (error, root) => { if (error) throw error; root = d3.hierarchy(root); root.sum(d => d.size); const slice = svg.selectAll('g.slice').data(partition(root).descendants()); slice.exit().remove(); const newSlice = slice.enter().append('g').attr('class', 'slice').on('click', d => { d3.event.stopPropagation(); focusOn(d); }); newSlice.append('title').text(d => d.data.name + '\n' + formatNumber(d.value)); newSlice.append('path').attr('class', 'main-arc') //Alternative 1 //.style('fill', d => color((d.children? d: d.parent).data.name)) //Alternative 2.style('fill', function(d) { return d.data.color || "red" }).attr('d', arc); newSlice.append('path').attr('class', 'hidden-arc').attr('id', (_, i) => `hiddenArc${i}`).attr('d', middleArcLine); const text = newSlice.append('text').attr('display', d => textFits(d)? null: 'none'); // Add white contour text.append('textPath').attr('startOffset', '50%').attr('xlink:href', (_, i) => `#hiddenArc${i}`).text(d => d.data.name).style('fill', 'none').style('stroke', '#fff').style('stroke-width', 5).style('stroke-linejoin', 'round'); text.append('textPath').attr('startOffset', '50%').attr('xlink:href', (_, i) => `#hiddenArc${i}`).text(d => d.data.name); }); function focusOn(d = { x0: 0, x1: 1, y0: 0, y1: 1 }) { // Reset to top-level if no data point specified const transition = svg.transition().duration(750).tween('scale', () => { const xd = d3.interpolate(x.domain(), [d.x0, d.x1]), yd = d3.interpolate(y.domain(), [d.y0, 1]); return t => { x.domain(xd(t)); y.domain(yd(t)); }; }); transition.selectAll('path.main-arc').attrTween('d', d => () => arc(d)); transition.selectAll('path.hidden-arc').attrTween('d', d => () => middleArcLine(d)); transition.selectAll('text').attrTween('display', d => () => textFits(d)? null: 'none'); moveStackToFront(d); // function moveStackToFront(elD) { svg.selectAll('.slice').filter(d => d === elD).each(function(d) { this.parentNode.appendChild(this); if (d.parent) { moveStackToFront(d.parent); } }) } } </script> </body>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.