This variant of a sunburst diagram shows only two layers of the hierarchy at a time. Click a node to zoom in, or the center to zoom out. Compare to an icicle.
Code
sunburst = {constroot=partition(flareData);root.each(d => d.current= d);const svg = d3.create("svg").attr("viewBox", [0,0, width, width]).style("font","15px sans-serif");const g = svg.append("g").attr("transform",`translate(${width /2},${width /2})`);const path = g.append("g").selectAll("path").data(root.descendants().slice(1)).join("path").attr("fill", d => { while (d.depth>1) d = d.parent;returncolor(d.data.name); }).attr("fill-opacity", d =>arcVisible(d.current) ? (d.children?0.6:0.4) :0).attr("d", d =>arc(d.current)); path.filter(d => d.children).style("cursor","pointer").on("click", clicked); path.append("title").text(d =>`${d.ancestors().map(d => d.data.name).reverse().join("/")}\n${format(d.value)}`);const label = g.append("g").attr("pointer-events","none").attr("text-anchor","middle").style("user-select","none").selectAll("text").data(root.descendants().slice(1)).join("text").attr("dy","0.35em").attr("fill-opacity", d =>+labelVisible(d.current)).attr("transform", d =>labelTransform(d.current)).text(d => d.data.name);const parent = g.append("circle").datum(root).attr("r", radius).attr("fill","none").attr("pointer-events","all").on("click", clicked);functionclicked(event, p) { parent.datum(p.parent||root);root.each(d => d.target= {x0:Math.max(0,Math.min(1, (d.x0- p.x0) / (p.x1- p.x0))) *2*Math.PI,x1:Math.max(0,Math.min(1, (d.x1- p.x0) / (p.x1- p.x0))) *2*Math.PI,y0:Math.max(0, d.y0- p.depth),y1:Math.max(0, d.y1- p.depth) });const t = g.transition().duration(750);// Transition the data on all arcs, even the ones that aren’t visible,// so that if this transition is interrupted, entering arcs will start// the next transition from the desired position. path.transition(t).tween("data", d => {const i = d3.interpolate(d.current, d.target);return t => d.current=i(t); }).filter(function(d) {return+this.getAttribute("fill-opacity") ||arcVisible(d.target); }).attr("fill-opacity", d =>arcVisible(d.target) ? (d.children?0.6:0.4) :0).attrTween("d", d => () =>arc(d.current)); label.filter(function(d) {return+this.getAttribute("fill-opacity") ||labelVisible(d.target); }).transition(t).attr("fill-opacity", d =>+labelVisible(d.target)).attrTween("transform", d => () =>labelTransform(d.current)); }functionarcVisible(d) {return d.y1<=3&& d.y0>=1&& d.x1> d.x0; }functionlabelVisible(d) {return d.y1<=3&& d.y0>=1&& (d.y1- d.y0) * (d.x1- d.x0) >0.03; }functionlabelTransform(d) {const x = (d.x0+ d.x1) /2*180/Math.PI;const y = (d.y0+ d.y1) /2* radius;return`rotate(${x -90}) translate(${y},0) rotate(${x <180?0:180})`; }return svg.node();}
---title: "Sunburst"subtitle: "Originally published at <https://observablehq.com/@d3/zoomable-sunburst>"author: "Mike Bostock"date: "2018-04-30"license: ISC Licenseformat: html: toc: false code-tools: true---This variant of a [sunburst diagram](https://observablehq.com/@d3/sunburst) shows only two layers of the hierarchy at a time. Click a node to zoom in, or the center to zoom out. Compare to an [icicle](https://observablehq.com/@d3/zoomable-icicle).```{ojs}//| code-fold: truesunburst = {constroot=partition(flareData);root.each(d => d.current= d);const svg = d3.create("svg").attr("viewBox", [0,0, width, width]).style("font","15px sans-serif");const g = svg.append("g").attr("transform",`translate(${width /2},${width /2})`);const path = g.append("g").selectAll("path").data(root.descendants().slice(1)).join("path").attr("fill", d => { while (d.depth>1) d = d.parent;returncolor(d.data.name); }).attr("fill-opacity", d =>arcVisible(d.current) ? (d.children?0.6:0.4) :0).attr("d", d =>arc(d.current)); path.filter(d => d.children).style("cursor","pointer").on("click", clicked); path.append("title").text(d =>`${d.ancestors().map(d => d.data.name).reverse().join("/")}\n${format(d.value)}`);const label = g.append("g").attr("pointer-events","none").attr("text-anchor","middle").style("user-select","none").selectAll("text").data(root.descendants().slice(1)).join("text").attr("dy","0.35em").attr("fill-opacity", d =>+labelVisible(d.current)).attr("transform", d =>labelTransform(d.current)).text(d => d.data.name);const parent = g.append("circle").datum(root).attr("r", radius).attr("fill","none").attr("pointer-events","all").on("click", clicked);functionclicked(event, p) { parent.datum(p.parent||root);root.each(d => d.target= {x0:Math.max(0,Math.min(1, (d.x0- p.x0) / (p.x1- p.x0))) *2*Math.PI,x1:Math.max(0,Math.min(1, (d.x1- p.x0) / (p.x1- p.x0))) *2*Math.PI,y0:Math.max(0, d.y0- p.depth),y1:Math.max(0, d.y1- p.depth) });const t = g.transition().duration(750);// Transition the data on all arcs, even the ones that aren’t visible,// so that if this transition is interrupted, entering arcs will start// the next transition from the desired position. path.transition(t).tween("data", d => {const i = d3.interpolate(d.current, d.target);return t => d.current=i(t); }).filter(function(d) {return+this.getAttribute("fill-opacity") ||arcVisible(d.target); }).attr("fill-opacity", d =>arcVisible(d.target) ? (d.children?0.6:0.4) :0).attrTween("d", d => () =>arc(d.current)); label.filter(function(d) {return+this.getAttribute("fill-opacity") ||labelVisible(d.target); }).transition(t).attr("fill-opacity", d =>+labelVisible(d.target)).attrTween("transform", d => () =>labelTransform(d.current)); }functionarcVisible(d) {return d.y1<=3&& d.y0>=1&& d.x1> d.x0; }functionlabelVisible(d) {return d.y1<=3&& d.y0>=1&& (d.y1- d.y0) * (d.x1- d.x0) >0.03; }functionlabelTransform(d) {const x = (d.x0+ d.x1) /2*180/Math.PI;const y = (d.y0+ d.y1) /2* radius;return`rotate(${x -90}) translate(${y},0) rotate(${x <180?0:180})`; }return svg.node();}``````{ojs}flareData =FileAttachment("flare-2.json").json()partition = flareData => {constroot= d3.hierarchy(flareData).sum(d => d.value).sort((a, b) => b.value- a.value);return d3.partition().size([2*Math.PI,root.height+1]) (root);}color = d3.scaleOrdinal( d3.quantize(d3.interpolateRainbow, flareData.children.length+1))format = d3.format(",d")width =932radius = width /6arc = d3.arc().startAngle(d => d.x0).endAngle(d => d.x1).padAngle(d =>Math.min((d.x1- d.x0) /2,0.005)).padRadius(radius *1.5).innerRadius(d => d.y0* radius).outerRadius(d =>Math.max(d.y0* radius, d.y1* radius -1))```