如何使 d3 sunburst 从 3 点开始?

How to make d3 sunburst starting at 3 o'clock?

我正在用这个例子画旭日图,http://www.jasondavies.com/coffee-wheel/。我发现大多数旭日图从 12 点开始为 0 度。 如何更改代码以使其在 3 点钟开始?

我尝试更改代码:

x = d3.scale.linear().range([0, 2 * Math.PI]),

x = d3.scale.linear().range([90, 2 * Math.PI+90]),

但这行不通。

可能最简单的方法是实际旋转包含可视化的 SVG 组。

<svg>
    <g transform="rotate(90)">
    ... // sunburst goes here
    <g>
<svg>

我建议重写示例中与渲染相关的部分。

示例中使用的分区布局不处理角度和旋转,它们由示例中的代码派生。需要处理三个轮换:

  • 圆弧形区域的旋转。
  • 文本围绕图表中心旋转。
  • 文本围绕其中心旋转。

起点

这是改编为代码片段的原始奶酪轮:

var width = 840,
  height = width,
  radius = width / 2,
  x = d3.scale.linear().range([0, 2 * Math.PI]),
  y = d3.scale.pow().exponent(1.3).domain([0, 1]).range([0, radius]),
  padding = 5,
  duration = 1000;

var div = d3.select("body");

div.select("img").remove();

var vis = div.append("svg")
  .attr("width", width + padding * 2)
  .attr("height", height + padding * 2)
  .append("g")
  .attr("transform", "translate(" + [radius + padding, radius + padding] + ")");

div.append("p")
  .attr("id", "intro")
  .text("Click to zoom!");

var partition = d3.layout.partition()
  .sort(null)
  .value(function(d) {
    return 5.8 - d.depth;
  });

var arc = d3.svg.arc()
  .startAngle(function(d) {
    return Math.max(0, Math.min(2 * Math.PI, x(d.x)));
  })
  .endAngle(function(d) {
    return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx)));
  })
  .innerRadius(function(d) {
    return Math.max(0, d.y ? y(d.y) : d.y);
  })
  .outerRadius(function(d) {
    return Math.max(0, y(d.y + d.dy));
  });

var json = getData();

var nodes = partition.nodes({ children: json });

var path = vis.selectAll("path").data(nodes);
path.enter().append("path")
  .attr("id", function(d, i) {
    return "path-" + i;
  })
  .attr("d", arc)
  .attr("fill-rule", "evenodd")
  .style("fill", colour)
  .on("click", click);

var text = vis.selectAll("text").data(nodes);
var textEnter = text.enter().append("text")
  .style("fill-opacity", 1)
  .style("fill", function(d) {
    return brightness(d3.rgb(colour(d))) < 125 ? "#eee" : "#000";
  })
  .attr("text-anchor", function(d) {
    return x(d.x + d.dx / 2) > Math.PI ? "end" : "start";
  })
  .attr("dy", ".2em")
  .attr("transform", function(d) {
    var multiline = (d.name || "").split(" ").length > 1,
      angle = x(d.x + d.dx / 2) * 180 / Math.PI - 90,
      rotate = angle + (multiline ? -.5 : 0);
    return "rotate(" + rotate + ")translate(" + (y(d.y) + padding) + ")rotate(" + (angle > 90 ? -180 : 0) + ")";
  })
  .on("click", click);
textEnter.append("tspan")
  .attr("x", 0)
  .text(function(d) {
    return d.depth ? d.name.split(" ")[0] : "";
  });
textEnter.append("tspan")
  .attr("x", 0)
  .attr("dy", "1em")
  .text(function(d) {
    return d.depth ? d.name.split(" ")[1] || "" : "";
  });

function click(d) {
  path.transition()
    .duration(duration)
    .attrTween("d", arcTween(d));

  // Somewhat of a hack as we rely on arcTween updating the scales.
  text.style("visibility", function(e) {
      return isParentOf(d, e) ? null : d3.select(this).style("visibility");
    })
    .transition()
    .duration(duration)
    .attrTween("text-anchor", function(d) {
      return function() {
        return x(d.x + d.dx / 2) > Math.PI ? "end" : "start";
      };
    })
    .attrTween("transform", function(d) {
      var multiline = (d.name || "").split(" ").length > 1;
      return function() {
        var angle = x(d.x + d.dx / 2) * 180 / Math.PI - 90,
          rotate = angle + (multiline ? -.5 : 0);
        return "rotate(" + rotate + ")translate(" + (y(d.y) + padding) + ")rotate(" + (angle > 90 ? -180 : 0) + ")";
      };
    })
    .style("fill-opacity", function(e) {
      return isParentOf(d, e) ? 1 : 1e-6;
    })
    .each("end", function(e) {
      d3.select(this).style("visibility", isParentOf(d, e) ? null : "hidden");
    });
};

function isParentOf(p, c) {
  if (p === c) return true;
  if (p.children) {
    return p.children.some(function(d) {
      return isParentOf(d, c);
    });
  }
  return false;
}

function colour(d) {
  if (d.children) {
    // There is a maximum of two children!
    var colours = d.children.map(colour),
      a = d3.hsl(colours[0]),
      b = d3.hsl(colours[1]);
    // L*a*b* might be better here...
    return d3.hsl((a.h + b.h) / 2, a.s * 1.2, a.l / 1.2);
  }
  return d.colour || "#fff";
}

// Interpolate the scales!
function arcTween(d) {
  var my = maxY(d),
    xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]),
    yd = d3.interpolate(y.domain(), [d.y, my]),
    yr = d3.interpolate(y.range(), [d.y ? 20 : 0, radius]);
  return function(d) {
    return function(t) {
      x.domain(xd(t));
      y.domain(yd(t)).range(yr(t));
      return arc(d);
    };
  };
}

function maxY(d) {
  return d.children ? Math.max.apply(Math, d.children.map(maxY)) : d.y + d.dy;
}

// http://www.w3.org/WAI/ER/WD-AERT/#color-contrast
function brightness(rgb) {
  return rgb.r * .299 + rgb.g * .587 + rgb.b * .114;
}


function getData(rgb) {
  return [{
    "name": "Aromas",
    "children": [{
      "name": "Enzymatic",
      "children": [{
        "name": "Flowery",
        "children": [{
          "name": "Floral",
          "children": [{
            "name": "Coffee Blossom",
            "colour": "#f9f0ab"
          }, {
            "name": "Tea Rose",
            "colour": "#e8e596"
          }]
        }, {
          "name": "Fragrant",
          "children": [{
            "name": "Cardamon Caraway",
            "colour": "#f0e2a3"
          }, {
            "name": "Coriander Seeds",
            "colour": "#ede487"
          }]
        }]
      }, {
        "name": "Fruity",
        "children": [{
          "name": "Citrus",
          "children": [{
            "name": "Lemon",
            "colour": "#efd580"
          }, {
            "name": "Apple",
            "colour": "#f1cb82"
          }]
        }, {
          "name": "Berry-like",
          "children": [{
            "name": "Apricot",
            "colour": "#f1c298"
          }, {
            "name": "Blackberry",
            "colour": "#e8b598"
          }]
        }]
      }, {
        "name": "Herby",
        "children": [{
          "name": "Alliaceous",
          "children": [{
            "name": "Onion",
            "colour": "#d5dda1"
          }, {
            "name": "Garlic",
            "colour": "#c9d2b5"
          }]
        }, {
          "name": "Leguminous",
          "children": [{
            "name": "Cucumber",
            "colour": "#aec1ad"
          }, {
            "name": "Garden Peas",
            "colour": "#a7b8a8"
          }]
        }]
      }]
    }, {
      "name": "Sugar Browning",
      "children": [{
        "name": "Nutty",
        "children": [{
          "name": "Nut-like",
          "children": [{
            "name": "Roasted Peanuts",
            "colour": "#b49a3d"
          }, {
            "name": "Walnuts",
            "colour": "#b28647"
          }]
        }, {
          "name": "Malt-like",
          "children": [{
            "name": "Balsamic Rice",
            "colour": "#a97d32"
          }, {
            "name": "Toast",
            "colour": "#b68334"
          }]
        }]
      }, {
        "name": "Carmelly",
        "children": [{
          "name": "Candy-like",
          "children": [{
            "name": "Roasted Hazelnut",
            "colour": "#d6a680"
          }, {
            "name": "Roasted Almond",
            "colour": "#dfad70"
          }]
        }, {
          "name": "Syrup-like",
          "children": [{
            "name": "Honey",
            "colour": "#a2765d"
          }, {
            "name": "Maple Syrup",
            "colour": "#9f6652"
          }]
        }]
      }, {
        "name": "Chocolatey",
        "children": [{
          "name": "Chocolate-like",
          "children": [{
            "name": "Bakers",
            "colour": "#b9763f"
          }, {
            "name": "Dark Chocolate",
            "colour": "#bf6e5d"
          }]
        }, {
          "name": "Vanilla-like",
          "children": [{
            "name": "Swiss",
            "colour": "#af643c"
          }, {
            "name": "Butter",
            "colour": "#9b4c3f"
          }]
        }]
      }]
    }, {
      "name": "Dry Distillation",
      "children": [{
        "name": "Resinous",
        "children": [{
          "name": "Turpeny",
          "children": [{
            "name": "Piney",
            "colour": "#72659d"
          }, {
            "name": "Blackcurrant-like",
            "colour": "#8a6e9e"
          }]
        }, {
          "name": "Medicinal",
          "children": [{
            "name": "Camphoric",
            "colour": "#8f5c85"
          }, {
            "name": "Cineolic",
            "colour": "#934b8b"
          }]
        }]
      }, {
        "name": "Spicy",
        "children": [{
          "name": "Warming",
          "children": [{
            "name": "Cedar",
            "colour": "#9d4e87"
          }, {
            "name": "Pepper",
            "colour": "#92538c"
          }]
        }, {
          "name": "Pungent",
          "children": [{
            "name": "Clove",
            "colour": "#8b6397"
          }, {
            "name": "Thyme",
            "colour": "#716084"
          }]
        }]
      }, {
        "name": "Carbony",
        "children": [{
          "name": "Smokey",
          "children": [{
            "name": "Tarry",
            "colour": "#2e6093"
          }, {
            "name": "Pipe Tobacco",
            "colour": "#3a5988"
          }]
        }, {
          "name": "Ashy",
          "children": [{
            "name": "Burnt",
            "colour": "#4a5072"
          }, {
            "name": "Charred",
            "colour": "#393e64"
          }]
        }]
      }]
    }]
  }, {
    "name": "Tastes",
    "children": [{
      "name": "Bitter",
      "children": [{
        "name": "Pungent",
        "children": [{
          "name": "Creosol",
          "colour": "#aaa1cc"
        }, {
          "name": "Phenolic",
          "colour": "#e0b5c9"
        }]
      }, {
        "name": "Harsh",
        "children": [{
          "name": "Caustic",
          "colour": "#e098b0"
        }, {
          "name": "Alkaline",
          "colour": "#ee82a2"
        }]
      }]
    }, {
      "name": "Salt",
      "children": [{
        "name": "Sharp",
        "children": [{
          "name": "Astringent",
          "colour": "#ef91ac"
        }, {
          "name": "Rough",
          "colour": "#eda994"
        }]
      }, {
        "name": "Bland",
        "children": [{
          "name": "Neutral",
          "colour": "#eeb798"
        }, {
          "name": "Soft",
          "colour": "#ecc099"
        }]
      }]
    }, {
      "name": "Sweet",
      "children": [{
        "name": "Mellow",
        "children": [{
          "name": "Delicate",
          "colour": "#f6d5aa"
        }, {
          "name": "Mild",
          "colour": "#f0d48a"
        }]
      }, {
        "name": "Acidy",
        "children": [{
          "name": "Nippy",
          "colour": "#efd95f"
        }, {
          "name": "Piquant",
          "colour": "#eee469"
        }]
      }]
    }, {
      "name": "Sour",
      "children": [{
        "name": "Winey",
        "children": [{
          "name": "Tangy",
          "colour": "#dbdc7f"
        }, {
          "name": "Tart",
          "colour": "#dfd961"
        }]
      }, {
        "name": "Soury",
        "children": [{
          "name": "Hard",
          "colour": "#ebe378"
        }, {
          "name": "Acrid",
          "colour": "#f5e351"
        }]
      }]
    }]
  }];
};
body {
  font-size: 1em;
  font-weight: 400;
  word-spacing: normal;
  letter-spacing: normal;
  text-transform: none;
  font-family: Verdana, Myriad Web, Syntax, sans-serif;
  font-size-adjust: .58;
  color: #000;
  background: #FFF;
  line-height: 1.58em;
  border-top: 0;
  border-left: 0;
  border-bottom: 0;
  border-right: 0;
  width: auto;
  margin: 1.58em 5% 1.58em 8%;
  padding: 0
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

旋转背景区域

代替此代码:

  .startAngle(function(d) {
    return Math.max(0, Math.min(2 * Math.PI, x(d.x)));
  })
  .endAngle(function(d) {
    return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx)));
  })

我们需要这个:

  .startAngle(function(d) {
    return Math.PI/2 + Math.max(0, Math.min(2 * Math.PI, x(d.x)));
  })
  .endAngle(function(d) {
    return Math.PI/2 + Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx)));
  })

(数学。PI/2 被添加到两个 return 值)

结果是:

旋转文本

旋转文本的类似更改,请参阅下面代码段中的代码。

最终结果

var width = 840,
  height = width,
  radius = width / 2,
  x = d3.scale.linear().range([0, 2 * Math.PI]),
  y = d3.scale.pow().exponent(1.3).domain([0, 1]).range([0, radius]),
  padding = 5,
  duration = 1000;

var div = d3.select("body");

div.select("img").remove();

var vis = div.append("svg")
  .attr("width", width + padding * 2)
  .attr("height", height + padding * 2)
  .append("g")
  .attr("transform", "translate(" + [radius + padding, radius + padding] + ")");

div.append("p")
  .attr("id", "intro")
  .text("Click to zoom!");

var partition = d3.layout.partition()
  .sort(null)
  .value(function(d) {
    return 5.8 - d.depth;
  });

var arc = d3.svg.arc()
  .startAngle(function(d) {
    return Math.PI/2 + Math.max(0, Math.min(2 * Math.PI, x(d.x)));
  })
  .endAngle(function(d) {
    return Math.PI/2 + Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx)));
  })
  .innerRadius(function(d) {
    return Math.max(0, d.y ? y(d.y) : d.y);
  })
  .outerRadius(function(d) {
    return Math.max(0, y(d.y + d.dy));
  });

var json = getData();

var nodes = partition.nodes({ children: json });

var path = vis.selectAll("path").data(nodes);
path.enter().append("path")
  .attr("id", function(d, i) {
    return "path-" + i;
  })
  .attr("d", arc)
  .attr("fill-rule", "evenodd")
  .style("fill", colour)
  .on("click", click);

var text = vis.selectAll("text").data(nodes);
var textEnter = text.enter().append("text")
  .style("fill-opacity", 1)
  .style("fill", function(d) {
    return brightness(d3.rgb(colour(d))) < 125 ? "#eee" : "#000";
  })
  .attr("text-anchor", function(d) {
    return ((x(d.x + d.dx / 2) > Math.PI/2)&&(x(d.x + d.dx / 2) < 3*Math.PI/2)) ? "end" : "start";
  })
  .attr("dy", ".2em")
  .attr("transform", function(d) {
    var multiline = (d.name || "").split(" ").length > 1,
      angle = x(d.x + d.dx / 2) * 180 / Math.PI,
      rotate = angle + (multiline ? -.5 : 0);
    return "rotate(" + rotate + ")translate(" + (y(d.y) + padding) + ")rotate(" + ((angle > 90) && (angle < 270)  ? -180 : 0) + ")";
  })
  .on("click", click);
textEnter.append("tspan")
  .attr("x", 0)
  .text(function(d) {
    return d.depth ? d.name.split(" ")[0] : "";
  });
textEnter.append("tspan")
  .attr("x", 0)
  .attr("dy", "1em")
  .text(function(d) {
    return d.depth ? d.name.split(" ")[1] || "" : "";
  });

function click(d) {
  path.transition()
    .duration(duration)
    .attrTween("d", arcTween(d));

  // Somewhat of a hack as we rely on arcTween updating the scales.
  text.style("visibility", function(e) {
      return isParentOf(d, e) ? null : d3.select(this).style("visibility");
    })
    .transition()
    .duration(duration)
    .attrTween("text-anchor", function(d) {
      return function() {
        return ((x(d.x + d.dx / 2) > Math.PI/2)&&(x(d.x + d.dx / 2) < 3*Math.PI/2)) ? "end" : "start";
      };
    })
    .attrTween("transform", function(d) {
      var multiline = (d.name || "").split(" ").length > 1;
      return function() {
        var angle = x(d.x + d.dx / 2) * 180 / Math.PI,
          rotate = angle + (multiline ? -.5 : 0);
//      rotate = ((angle > 2*Math.PI) ? angle-2*Math.PI : angle) + (multiline ? -.5 : 0);
        //  if(d.level==1) rotate = 0;
//        return "rotate(" + rotate + ")translate(" + (y(d.y) + padding) + ")rotate(" + (angle > 180 ? -180 : 0) + ")";
    return "rotate(" + rotate + ")translate(" + (y(d.y) + padding) + ")rotate(" + ((angle > 90) && (angle < 270)  ? -180 : 0) + ")";
        
      };
    })
    .style("fill-opacity", function(e) {
      return isParentOf(d, e) ? 1 : 1e-6;
    })
    .each("end", function(e) {
      d3.select(this).style("visibility", isParentOf(d, e) ? null : "hidden");
    });
};

function isParentOf(p, c) {
  if (p === c) return true;
  if (p.children) {
    return p.children.some(function(d) {
      return isParentOf(d, c);
    });
  }
  return false;
}

function colour(d) {
  if (d.children) {
    // There is a maximum of two children!
    var colours = d.children.map(colour),
      a = d3.hsl(colours[0]),
      b = d3.hsl(colours[1]);
    // L*a*b* might be better here...
    return d3.hsl((a.h + b.h) / 2, a.s * 1.2, a.l / 1.2);
  }
  return d.colour || "#fff";
}

// Interpolate the scales!
function arcTween(d) {
  var my = maxY(d),
    xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]),
    yd = d3.interpolate(y.domain(), [d.y, my]),
    yr = d3.interpolate(y.range(), [d.y ? 20 : 0, radius]);
  return function(d) {
    return function(t) {
      x.domain(xd(t));
      y.domain(yd(t)).range(yr(t));
      return arc(d);
    };
  };
}

function maxY(d) {
  return d.children ? Math.max.apply(Math, d.children.map(maxY)) : d.y + d.dy;
}

// http://www.w3.org/WAI/ER/WD-AERT/#color-contrast
function brightness(rgb) {
  return rgb.r * .299 + rgb.g * .587 + rgb.b * .114;
}


function getData(rgb) {
  return [{
    "name": "Aromas",
    "children": [{
      "name": "Enzymatic",
      "children": [{
        "name": "Flowery",
        "children": [{
          "name": "Floral",
          "children": [{
            "name": "Coffee Blossom",
            "colour": "#f9f0ab"
          }, {
            "name": "Tea Rose",
            "colour": "#e8e596"
          }]
        }, {
          "name": "Fragrant",
          "children": [{
            "name": "Cardamon Caraway",
            "colour": "#f0e2a3"
          }, {
            "name": "Coriander Seeds",
            "colour": "#ede487"
          }]
        }]
      }, {
        "name": "Fruity",
        "children": [{
          "name": "Citrus",
          "children": [{
            "name": "Lemon",
            "colour": "#efd580"
          }, {
            "name": "Apple",
            "colour": "#f1cb82"
          }]
        }, {
          "name": "Berry-like",
          "children": [{
            "name": "Apricot",
            "colour": "#f1c298"
          }, {
            "name": "Blackberry",
            "colour": "#e8b598"
          }]
        }]
      }, {
        "name": "Herby",
        "children": [{
          "name": "Alliaceous",
          "children": [{
            "name": "Onion",
            "colour": "#d5dda1"
          }, {
            "name": "Garlic",
            "colour": "#c9d2b5"
          }]
        }, {
          "name": "Leguminous",
          "children": [{
            "name": "Cucumber",
            "colour": "#aec1ad"
          }, {
            "name": "Garden Peas",
            "colour": "#a7b8a8"
          }]
        }]
      }]
    }, {
      "name": "Sugar Browning",
      "children": [{
        "name": "Nutty",
        "children": [{
          "name": "Nut-like",
          "children": [{
            "name": "Roasted Peanuts",
            "colour": "#b49a3d"
          }, {
            "name": "Walnuts",
            "colour": "#b28647"
          }]
        }, {
          "name": "Malt-like",
          "children": [{
            "name": "Balsamic Rice",
            "colour": "#a97d32"
          }, {
            "name": "Toast",
            "colour": "#b68334"
          }]
        }]
      }, {
        "name": "Carmelly",
        "children": [{
          "name": "Candy-like",
          "children": [{
            "name": "Roasted Hazelnut",
            "colour": "#d6a680"
          }, {
            "name": "Roasted Almond",
            "colour": "#dfad70"
          }]
        }, {
          "name": "Syrup-like",
          "children": [{
            "name": "Honey",
            "colour": "#a2765d"
          }, {
            "name": "Maple Syrup",
            "colour": "#9f6652"
          }]
        }]
      }, {
        "name": "Chocolatey",
        "children": [{
          "name": "Chocolate-like",
          "children": [{
            "name": "Bakers",
            "colour": "#b9763f"
          }, {
            "name": "Dark Chocolate",
            "colour": "#bf6e5d"
          }]
        }, {
          "name": "Vanilla-like",
          "children": [{
            "name": "Swiss",
            "colour": "#af643c"
          }, {
            "name": "Butter",
            "colour": "#9b4c3f"
          }]
        }]
      }]
    }, {
      "name": "Dry Distillation",
      "children": [{
        "name": "Resinous",
        "children": [{
          "name": "Turpeny",
          "children": [{
            "name": "Piney",
            "colour": "#72659d"
          }, {
            "name": "Blackcurrant-like",
            "colour": "#8a6e9e"
          }]
        }, {
          "name": "Medicinal",
          "children": [{
            "name": "Camphoric",
            "colour": "#8f5c85"
          }, {
            "name": "Cineolic",
            "colour": "#934b8b"
          }]
        }]
      }, {
        "name": "Spicy",
        "children": [{
          "name": "Warming",
          "children": [{
            "name": "Cedar",
            "colour": "#9d4e87"
          }, {
            "name": "Pepper",
            "colour": "#92538c"
          }]
        }, {
          "name": "Pungent",
          "children": [{
            "name": "Clove",
            "colour": "#8b6397"
          }, {
            "name": "Thyme",
            "colour": "#716084"
          }]
        }]
      }, {
        "name": "Carbony",
        "children": [{
          "name": "Smokey",
          "children": [{
            "name": "Tarry",
            "colour": "#2e6093"
          }, {
            "name": "Pipe Tobacco",
            "colour": "#3a5988"
          }]
        }, {
          "name": "Ashy",
          "children": [{
            "name": "Burnt",
            "colour": "#4a5072"
          }, {
            "name": "Charred",
            "colour": "#393e64"
          }]
        }]
      }]
    }]
  }, {
    "name": "Tastes",
    "children": [{
      "name": "Bitter",
      "children": [{
        "name": "Pungent",
        "children": [{
          "name": "Creosol",
          "colour": "#aaa1cc"
        }, {
          "name": "Phenolic",
          "colour": "#e0b5c9"
        }]
      }, {
        "name": "Harsh",
        "children": [{
          "name": "Caustic",
          "colour": "#e098b0"
        }, {
          "name": "Alkaline",
          "colour": "#ee82a2"
        }]
      }]
    }, {
      "name": "Salt",
      "children": [{
        "name": "Sharp",
        "children": [{
          "name": "Astringent",
          "colour": "#ef91ac"
        }, {
          "name": "Rough",
          "colour": "#eda994"
        }]
      }, {
        "name": "Bland",
        "children": [{
          "name": "Neutral",
          "colour": "#eeb798"
        }, {
          "name": "Soft",
          "colour": "#ecc099"
        }]
      }]
    }, {
      "name": "Sweet",
      "children": [{
        "name": "Mellow",
        "children": [{
          "name": "Delicate",
          "colour": "#f6d5aa"
        }, {
          "name": "Mild",
          "colour": "#f0d48a"
        }]
      }, {
        "name": "Acidy",
        "children": [{
          "name": "Nippy",
          "colour": "#efd95f"
        }, {
          "name": "Piquant",
          "colour": "#eee469"
        }]
      }]
    }, {
      "name": "Sour",
      "children": [{
        "name": "Winey",
        "children": [{
          "name": "Tangy",
          "colour": "#dbdc7f"
        }, {
          "name": "Tart",
          "colour": "#dfd961"
        }]
      }, {
        "name": "Soury",
        "children": [{
          "name": "Hard",
          "colour": "#ebe378"
        }, {
          "name": "Acrid",
          "colour": "#f5e351"
        }]
      }]
    }]
  }];
};
body {
  font-size: 1em;
  font-weight: 400;
  word-spacing: normal;
  letter-spacing: normal;
  text-transform: none;
  font-family: Verdana, Myriad Web, Syntax, sans-serif;
  font-size-adjust: .58;
  color: #000;
  background: #FFF;
  line-height: 1.58em;
  border-top: 0;
  border-left: 0;
  border-bottom: 0;
  border-right: 0;
  width: auto;
  margin: 1.58em 5% 1.58em 8%;
  padding: 0
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>