2
votes

I'm in the process of creating a family-tree using D3. My dataset is indeed hierarchical, but the root node of the tree is the child. Each "child node" contains two "parent" nodes that represents each childs two parents. Here is an example of my data.

    {
    name: "Morgans Jumpin Jack Flash",
    imagePath: "",
    description: "",
    subTitle: "",
    body: "",
    icon: "",
    iconColor: "",
    gender: "m",
    parents: [
        {
            name: "Moganas Heart of Fire",
            imagePath: "",
            description: "",
            subTitle: "",
            body: "",
            icon: "",
            iconColor: "",
            gender: "f",
            parents: [
                {
                    name: "Elkhaus Ice Storm",
                    imagePath: "",
                    description: "",
                    subTitle: "",
                    body: "",
                    icon: "",
                    iconColor: "",
                    gender: "m",
                    parents: []
                },{
                    name: "Morganas First Love",
                    imagePath: "",
                    description: "",
                    subTitle: "",
                    body: "",
                    icon: "",
                    iconColor: "",
                    gender: "f",
                    parents: []
                },
            ]
        },{
            name: "Desperado Hogan von der Accani",
            imagePath: "",
            description: "",
            subTitle: "",
            body: "",
            icon: "",
            iconColor: "",
            gender: "m",
            parents: [
                {
                    name: "Jim von Aurachgrund",
                    imagePath: "",
                    description: "",
                    subTitle: "",
                    body: "",
                    icon: "",
                    iconColor: "",
                    gender: "m",
                    parents: []
                },{
                    name: "Heroina D. Altobella",
                    imagePath: "",
                    description: "",
                    subTitle: "",
                    body: "",
                    icon: "",
                    iconColor: "",
                    gender: "f",
                    parents: []
                },
            ]
        },
    ]
}

Each node in the tree represents a Dog. The idea here is that you can see a given Dogs pedigree by going up the family tree to the parents, grand parents, etc.

Is it possible to use the given dataset with d3.tree() without modifying the data? (I know that I could probably just rename "parents" to "children", but that would be INCREDIBLY confusing to the next person who looks at the data set.)

1

1 Answers

2
votes

You don't need to alter your original dataset, instead when you create the root using d3.hierarchy you can specify which property contains the "children":

var root = d3.hierarchy(data, function(d) {
   return d.parents;  
})

The second parameter is the "child" accessor, but you can use it to represent parents. I've just kept a left to right layout, but it would be fairly trivial to change it to a right to left layout:

var data = {
    name: "Morgans Jumpin Jack Flash",
    imagePath: "",
    description: "",
    subTitle: "",
    body: "",
    icon: "",
    iconColor: "",
    gender: "m",
    parents: [
        {
            name: "Moganas Heart of Fire",
            imagePath: "",
            description: "",
            subTitle: "",
            body: "",
            icon: "",
            iconColor: "",
            gender: "f",
            parents: [
                {
                    name: "Elkhaus Ice Storm",
                    imagePath: "",
                    description: "",
                    subTitle: "",
                    body: "",
                    icon: "",
                    iconColor: "",
                    gender: "m",
                    parents: []
                },{
                    name: "Morganas First Love",
                    imagePath: "",
                    description: "",
                    subTitle: "",
                    body: "",
                    icon: "",
                    iconColor: "",
                    gender: "f",
                    parents: []
                },
            ]
        },{
            name: "Desperado Hogan von der Accani",
            imagePath: "",
            description: "",
            subTitle: "",
            body: "",
            icon: "",
            iconColor: "",
            gender: "m",
            parents: [
                {
                    name: "Jim von Aurachgrund",
                    imagePath: "",
                    description: "",
                    subTitle: "",
                    body: "",
                    icon: "",
                    iconColor: "",
                    gender: "m",
                    parents: []
                },{
                    name: "Heroina D. Altobella",
                    imagePath: "",
                    description: "",
                    subTitle: "",
                    body: "",
                    icon: "",
                    iconColor: "",
                    gender: "f",
                    parents: []
                },
            ]
        },
    ]
}

var root = d3.hierarchy(data, function(d) {
  return d.parents;
})



var width =500;
var height = 300;
var margin = {left:100,top:50,right:100,bottom:50};

var svg = d3.select("body")
  .append("svg")
  .attr("width",width)
  .attr("height",height)
var g = svg.append("g")
  .attr("transform","translate("+margin.left+","+margin.top+")");



var tree = d3.tree().size([height-margin.top-margin.bottom,width-margin.left-margin.right]);
var path = d3.linkHorizontal().x(function(d) { return d.y; }).y(function(d) { return d.x; })
var layout = tree(root);

var link = g.selectAll(null)
  .data(layout.links())
  .enter().append("path")
  .attr("class","link")
  .attr("d", path)

var text = g.selectAll(null)
  .data(root.descendants())
  .enter().append("text")
  .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
.text(function(d) { return d.data.name; })
  .attr("y",-15)
  .attr("x",-10)

var node = g.selectAll(null)
  .data(root.descendants())
  .enter().append("circle")
  .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
  .attr("class","node")
  .attr("r",function(d) { return d.data.name == "" ? 0 : 8; });
path {
  fill:none;
  stroke: #888;
  stroke-width: 2px;
 }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>