Skip to content

Instantly share code, notes, and snippets.

@timelyportfolio
Last active November 17, 2017 04:31
Show Gist options
  • Save timelyportfolio/1d6ef911b8b6dce15d82a0d0cedb1396 to your computer and use it in GitHub Desktop.
Save timelyportfolio/1d6ef911b8b6dce15d82a0d0cedb1396 to your computer and use it in GitHub Desktop.
partsankey on rpart
license: mit
height: 650

This is the derivative version of the partition sankey, but instead of collapsing leaves, this partsankey visualizes rpart or recursive partitioning. See post.

Replicate in R

library(htmltools)
library(rpart)
library(d3r)
library(vcdExtra)  # for the Titanic dataset used in first post

data("Titanicp", package="vcdExtra")

fit <- rpart(
  survived ~ pclass + sex + age,
  data = Titanicp
)

fit_json <- d3_party(fit)

scr <- tags$script(HTML(
sprintf(
"
  var titanic = %s

  var hier = d3.hierarchy(titanic)
  var width = 800;
  var height = 600;
  var nodeWidth = 10;
  var color = d3.scaleOrdinal(d3.schemeCategory10);
  // rearrange so that survived yes is green
  //  and no is red
  color.range(
    [color.range()[2]]
      .concat([color.range()[3]])
      .concat(color.range().splice(0,2))
      .concat(color.range().splice(4,10))
  )
  color.domain(['2', '1'])

  
  var svg = d3.select('#vis').append('svg')
    .style('width',width + 20 + 20)
    .style('height',height + 20 + 20)
    .append('g')
    .attr('transform','translate(20,20)');

  // n will represent sum at each split
  //  so don't use hier.sum
  //  instead add value attribute
  hier.each(function(d) {d.value = d.data.wt})

  // caution will mutate the object
  layout(hier, nodeWidth, 0.75)

  // note, this will not follow traditional d3 call form
  //  if we were to make this official change this to svg.call
  var nodes = drawNodes(hier, svg)

  var links = drawLinks(nodes, svg)

  // add mouseover that highlights with higher opacity
  //  this will highlight all children with same leaf name
  svg.selectAll('.link').on('mouseover', function(d) {
    d3.select(this).style('opacity', 0.8)
    if(d.target.linkPaths) {
      d.target.descendants().forEach(function(dd) {
        if(dd.linkPaths){
          dd.linkPaths.forEach(function(lp) {
            var data = d3.select(lp).datum();
            if(data.leaf == d.leaf) {
              d3.select(lp).style('opacity', 0.8)
            }
          })
        }
      })
    }
  })

  svg.selectAll('.link').on('mouseout', function(d) {
    svg.selectAll('.link').style('opacity', 0.5)
  })

  function layout(hier, nodeWidth, nodeHeightRatio) {
    nodeWidth = nodeWidth ? nodeWidth : 10;
    nodeHeightRatio = nodeHeightRatio ? nodeHeightRatio : 0.66;
    var nodeHeight = height * nodeHeightRatio;
    
    // run treemap slice to get heights
    //  note, this will overwrite the x0,x1,y0,y1
    d3.treemap()
      .size([nodeWidth, nodeHeight])
      .tile(d3.treemapSlice)(hier);

    // record treemap heights and widths
    //  since partition will overwrite
    hier.each(function(d) {
      d.h = d.y1 - d.y0;
      d.w = d.x1 - d.x0;
    })

    // now run partition with no size
    //  so will be in range [0,1]
    d3.partition()(hier);
  }

  function drawNodes(hier, svg) {
    var nodes = svg.selectAll('g.node')
      .data(hier.descendants());
    
    nodes = nodes.merge(
      nodes.enter().append('g')
        .attr('class','node')
    );
    
    nodes.attr('transform', function(d) {
      return 'translate(' + d.y0 * width  + ',' + d.x0 * height + ')'
    });
    
    nodes.append('rect')
      .classed('rect-part', true);
    
    nodes.append('text')
      //.style('text-anchor','end')
      .attr('dy','0.5em')
      .text(function(d) { return d.data.description});

    nodes.selectAll('rect.rect-part')
      .style('fill', 'gray')//function(d) {return color(d.data.name)})
      .style('stroke', 'white')
      //.transition()
      //.duration(duration)
      //.delay(delay)
      .attr('y', function(d) {
        return ((d.x1-d.x0)*height-d.h)/2;
      })
      .attr('width', function(d) { return nodeWidth; })
      .attr('height', function(d) {
        return d.h;
      });
      
  nodes.selectAll('text')
    .attr('y', function(d) {
      if(d.height > 0) {
      return ((d.x1-d.x0)*height-d.h)/2;
    }
      return (d.x1-d.x0)*height/2;
    })
    .attr('x', function(d) {
      if(d.height > 0) {
        return nodeWidth / 2
      }
      return nodeWidth
    })
    .attr('dy', function(d) {
      if(d.height > 0) {
        return '-0.15em'
      }
      return '0.25em'
    })
    .style('text-anchor', function(d) {
      if(d.height > 0) {
        return 'middle'
      }
      return 'start'
    })

  
      
    return nodes;    
  }

  function drawLinks(nodes, svg) {
    function stackSource(x) {
      var xobj = {}
      var sum = x.data.wt
      x.children.forEach(function(d) {
        // sum by response by using leaf data
        var leafdat = d.leaves().map(function(lf) {
          return lf.data.size.size[0]
        })
        var sizes = d3.zip(
          d3.merge(leafdat.map(function(d){return d.response})),
          d3.merge(leafdat.map(function(d){return d.freq}))
        )
        var sumsResponse = d3.nest()
          .key(function(d){return d[0]})
          .rollup(function(d){
            return d3.sum(d.map(function(dd){return dd[1]}))
          })
          .entries(sizes)
        sumsResponse.forEach(function(dd) {
          xobj[d.data.id + '~' + dd.key] = dd.value/sum;
        })
      })

      return d3.stack().keys(Object.keys(xobj))([xobj]);
    }

    function stackTarget(x) {
      // sum by response by using leaf data
      var leafdat = x.leaves().map(function(d) {
        return d.data.size.size[0]
      })
      var sizes = d3.zip(
        d3.merge(leafdat.map(function(d){return d.response})),
        d3.merge(leafdat.map(function(d){return d.freq}))
      )
      var sumsResponse = d3.nest()
        .key(function(d){return d[0]})
        .rollup(function(d){
          return d3.sum(d.map(function(dd){return dd[1]}))
        })
        .entries(sizes)
      var xobj = {};
      var sum = d3.sum(sumsResponse.map(function(d){
        return d.value
      }))
      sumsResponse.forEach(function(d) {
        xobj[d.key] = d.value/sum;
      })
      return d3.stack().keys(Object.keys(xobj))([xobj]);
    }

  
    nodes.each(function(node) {
      if(node.height == 0) {return}

      // empty array to store links on each node
      node.linkPaths = node.linkPaths ? node.linkPaths : [];
  
      function customLine(pts) {
        var ld = d3.linkHorizontal()
          .source(function(d){return d[0]})
          .target(function(d){return d[1]})
          .x(function(d){return d[0]})
          .y(function(d){return d[1]});
        return [
          ld([pts[0],pts[1]]),
          pts[1] + ',' + pts[2],
          ld([pts[2],pts[3]]).slice(1)
        ].join('L');
      }

      var st1 = stackSource(node);

      st1.forEach(function(d) {
        var childname = d.key.split('~')[0]
        var leafname = d.key.split('~')[1]

        var child = node.children.filter(function(ch) {
          return ch.data.id == childname
        })[0]

        var st = stackTarget(child).filter(function(d) {
          return d.key === leafname
        })[0];

        var link = svg.append('path')
          .classed('link', true)
          .style('opacity', 0.000001)

        link.datum({
          source: node,
          target: child,
          leaf: leafname
        })

        link.attr('d',customLine([
          [node.y0 * width + nodeWidth, ((node.x0 * height) + ((node.x1-node.x0)*height-node.h)/2 ) + d[0][0]*node.h],
          [child.y0 * width, ((child.x0 * height) + ((child.x1-child.x0)*height-child.h)/2 ) + st[0][0]*child.h],
          [child.y0 * width, ((child.x0 * height) + ((child.x1-child.x0)*height-child.h)/2 ) + st[0][1]*child.h],
          [node.y0 * width + nodeWidth, ((node.x0 * height) + ((node.x1-node.x0)*height-node.h)/2 ) + d[0][1]*node.h],
        ]));
        
        link
          .style('stroke', 'white')
          .style('fill', color(leafname));
        
        link
          .transition()
          //.duration(500)
          //.delay(duration+delay)
          .style('opacity', 0.5);
        
        node.linkPaths = node.linkPaths.concat(link.node());
      })
    })
  }
"
  ,
  fit_json
)
))

browsable(
  tagList(
    d3r::d3_dep_v4(offline=FALSE),
    tags$div(id = "vis"),
    scr
  )
)

forked from timelyportfolio's block: partsankey static

forked from timelyportfolio's block: partsankey interactive

forked from timelyportfolio's block: partsankey interactive angled

library(htmltools)
library(rpart)
library(d3r)
library(vcdExtra) # for the Titanic dataset used in first post
data("Titanicp", package="vcdExtra")
fit <- rpart(
survived ~ pclass + sex + age,
data = Titanicp
)
fit_json <- d3_party(fit)
scr <- tags$script(HTML(
sprintf(
"
var titanic = %s
var hier = d3.hierarchy(titanic)
var width = 800;
var height = 600;
var nodeWidth = 10;
var color = d3.scaleOrdinal(d3.schemeCategory10);
// rearrange so that survived yes is green
// and no is red
color.range(
[color.range()[2]]
.concat([color.range()[3]])
.concat(color.range().splice(0,2))
.concat(color.range().splice(4,10))
)
color.domain(['2', '1'])
var svg = d3.select('#vis').append('svg')
.style('width',width + 20 + 20)
.style('height',height + 20 + 20)
.append('g')
.attr('transform','translate(20,20)');
// n will represent sum at each split
// so don't use hier.sum
// instead add value attribute
hier.each(function(d) {d.value = d.data.wt})
// caution will mutate the object
layout(hier, nodeWidth, 0.75)
// note, this will not follow traditional d3 call form
// if we were to make this official change this to svg.call
var nodes = drawNodes(hier, svg)
var links = drawLinks(nodes, svg)
// add mouseover that highlights with higher opacity
// this will highlight all children with same leaf name
svg.selectAll('.link').on('mouseover', function(d) {
d3.select(this).style('opacity', 0.8)
if(d.target.linkPaths) {
d.target.descendants().forEach(function(dd) {
if(dd.linkPaths){
dd.linkPaths.forEach(function(lp) {
var data = d3.select(lp).datum();
if(data.leaf == d.leaf) {
d3.select(lp).style('opacity', 0.8)
}
})
}
})
}
})
svg.selectAll('.link').on('mouseout', function(d) {
svg.selectAll('.link').style('opacity', 0.5)
})
function layout(hier, nodeWidth, nodeHeightRatio) {
nodeWidth = nodeWidth ? nodeWidth : 10;
nodeHeightRatio = nodeHeightRatio ? nodeHeightRatio : 0.66;
var nodeHeight = height * nodeHeightRatio;
// run treemap slice to get heights
// note, this will overwrite the x0,x1,y0,y1
d3.treemap()
.size([nodeWidth, nodeHeight])
.tile(d3.treemapSlice)(hier);
// record treemap heights and widths
// since partition will overwrite
hier.each(function(d) {
d.h = d.y1 - d.y0;
d.w = d.x1 - d.x0;
})
// now run partition with no size
// so will be in range [0,1]
d3.partition()(hier);
}
function drawNodes(hier, svg) {
var nodes = svg.selectAll('g.node')
.data(hier.descendants());
nodes = nodes.merge(
nodes.enter().append('g')
.attr('class','node')
);
nodes.attr('transform', function(d) {
return 'translate(' + d.y0 * width + ',' + d.x0 * height + ')'
});
nodes.append('rect')
.classed('rect-part', true);
nodes.append('text')
//.style('text-anchor','end')
.attr('dy','0.5em')
.text(function(d) { return d.data.description});
nodes.selectAll('rect.rect-part')
.style('fill', 'gray')//function(d) {return color(d.data.name)})
.style('stroke', 'white')
//.transition()
//.duration(duration)
//.delay(delay)
.attr('y', function(d) {
return ((d.x1-d.x0)*height-d.h)/2;
})
.attr('width', function(d) { return nodeWidth; })
.attr('height', function(d) {
return d.h;
});
nodes.selectAll('text')
.attr('y', function(d) {
if(d.height > 0) {
return ((d.x1-d.x0)*height-d.h)/2;
}
return (d.x1-d.x0)*height/2;
})
.attr('x', function(d) {
if(d.height > 0) {
return nodeWidth / 2
}
return nodeWidth
})
.attr('dy', function(d) {
if(d.height > 0) {
return '-0.15em'
}
return '0.25em'
})
.style('text-anchor', function(d) {
if(d.height > 0) {
return 'middle'
}
return 'start'
})
return nodes;
}
function drawLinks(nodes, svg) {
function stackSource(x) {
var xobj = {}
var sum = x.data.wt
x.children.forEach(function(d) {
// sum by response by using leaf data
var leafdat = d.leaves().map(function(lf) {
return lf.data.size.size[0]
})
var sizes = d3.zip(
d3.merge(leafdat.map(function(d){return d.response})),
d3.merge(leafdat.map(function(d){return d.freq}))
)
var sumsResponse = d3.nest()
.key(function(d){return d[0]})
.rollup(function(d){
return d3.sum(d.map(function(dd){return dd[1]}))
})
.entries(sizes)
sumsResponse.forEach(function(dd) {
xobj[d.data.id + '~' + dd.key] = dd.value/sum;
})
})
return d3.stack().keys(Object.keys(xobj))([xobj]);
}
function stackTarget(x) {
// sum by response by using leaf data
var leafdat = x.leaves().map(function(d) {
return d.data.size.size[0]
})
var sizes = d3.zip(
d3.merge(leafdat.map(function(d){return d.response})),
d3.merge(leafdat.map(function(d){return d.freq}))
)
var sumsResponse = d3.nest()
.key(function(d){return d[0]})
.rollup(function(d){
return d3.sum(d.map(function(dd){return dd[1]}))
})
.entries(sizes)
var xobj = {};
var sum = d3.sum(sumsResponse.map(function(d){
return d.value
}))
sumsResponse.forEach(function(d) {
xobj[d.key] = d.value/sum;
})
return d3.stack().keys(Object.keys(xobj))([xobj]);
}
nodes.each(function(node) {
if(node.height == 0) {return}
// empty array to store links on each node
node.linkPaths = node.linkPaths ? node.linkPaths : [];
function customLine(pts) {
var ld = d3.linkHorizontal()
.source(function(d){return d[0]})
.target(function(d){return d[1]})
.x(function(d){return d[0]})
.y(function(d){return d[1]});
return [
ld([pts[0],pts[1]]),
pts[1] + ',' + pts[2],
ld([pts[2],pts[3]]).slice(1)
].join('L');
}
var st1 = stackSource(node);
st1.forEach(function(d) {
var childname = d.key.split('~')[0]
var leafname = d.key.split('~')[1]
var child = node.children.filter(function(ch) {
return ch.data.id == childname
})[0]
var st = stackTarget(child).filter(function(d) {
return d.key === leafname
})[0];
var link = svg.append('path')
.classed('link', true)
.style('opacity', 0.000001)
link.datum({
source: node,
target: child,
leaf: leafname
})
link.attr('d',customLine([
[node.y0 * width + nodeWidth, ((node.x0 * height) + ((node.x1-node.x0)*height-node.h)/2 ) + d[0][0]*node.h],
[child.y0 * width, ((child.x0 * height) + ((child.x1-child.x0)*height-child.h)/2 ) + st[0][0]*child.h],
[child.y0 * width, ((child.x0 * height) + ((child.x1-child.x0)*height-child.h)/2 ) + st[0][1]*child.h],
[node.y0 * width + nodeWidth, ((node.x0 * height) + ((node.x1-node.x0)*height-node.h)/2 ) + d[0][1]*node.h],
]));
link
.style('stroke', 'white')
.style('fill', color(leafname));
link
.transition()
//.duration(500)
//.delay(duration+delay)
.style('opacity', 0.5);
node.linkPaths = node.linkPaths.concat(link.node());
})
})
}
"
,
fit_json
)
))
browsable(
tagList(
d3r::d3_dep_v4(offline=FALSE),
tags$div(id = "vis"),
scr
)
)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script src="https://unpkg.com/d3@4.11.0/build/d3.min.js"></script>
</head>
<body style="background-color:white;">
<div id="vis"></div>
<script>
var titanic = {"id":1,"split":{"varid":3,"breaks":[],"index":[2,1],"right":true,"prob":[1,0],"info":[]},"children":[{"id":2,"split":{"varid":4,"breaks":9.5,"index":[2,1],"right":false,"prob":[1,0],"info":[]},"children":[{"id":3,"split":[],"surrogates":[],"info":[],"description":" age >= 9.5","rule":"sex %in% c(\"male\") & age >= 9.5","var":1,"n":800,"wt":800,"dev":136,"yval":1,"complexity":0,"ncompete":0,"nsurrogate":0,"yval2":[[1,664,136,0.83,0.17,0.6112]],"size":{"fitted":3,"size":[{"response":[1,2],"freq":[664,136]}]}},{"id":4,"split":{"varid":2,"breaks":[],"index":[2,2,1],"right":true,"prob":[1,0],"info":[]},"children":[{"id":5,"split":[],"surrogates":[],"info":[],"description":" pclass in 3rd","rule":"sex %in% c(\"male\") & age < 9.5 & pclass %in% c(\"3rd\")","var":1,"n":29,"wt":29,"dev":11,"yval":1,"complexity":0,"ncompete":0,"nsurrogate":0,"yval2":[[1,18,11,0.6207,0.3793,0.0222]],"size":{"fitted":5,"size":[{"response":[1,2],"freq":[18,11]}]}},{"id":6,"split":[],"surrogates":[],"info":[],"description":" pclass in 1st, 2nd","rule":"sex %in% c(\"male\") & age < 9.5 & pclass %in% c(\"1st\", \"2nd\")","var":1,"n":14,"wt":14,"dev":0,"yval":2,"complexity":0.01,"ncompete":0,"nsurrogate":0,"yval2":[[2,0,14,0,1,0.0107]],"size":{"fitted":6,"size":[{"response":[1,2],"freq":[0,14]}]}}],"surrogates":[],"info":[],"description":" age < 9.5","rule":"sex %in% c(\"male\") & age < 9.5","var":3,"n":43,"wt":43,"dev":18,"yval":2,"complexity":0.014,"ncompete":1,"nsurrogate":0,"yval2":[[2,18,25,0.4186,0.5814,0.0328]],"size":{"fitted":[],"size":[]}}],"surrogates":[],"info":[],"description":" sex in male","rule":"sex %in% c(\"male\")","var":2,"n":886,"wt":843,"dev":161,"yval":1,"complexity":0.014,"ncompete":1,"nsurrogate":0,"yval2":[[1,682,161,0.809,0.191,0.644]],"size":{"fitted":[],"size":[]}},{"id":7,"split":[],"surrogates":[],"info":[],"description":" sex in female","rule":"sex %in% c(\"female\")","var":1,"n":466,"wt":466,"dev":127,"yval":2,"complexity":0.008,"ncompete":0,"nsurrogate":0,"yval2":[[2,127,339,0.2725,0.7275,0.356]],"size":{"fitted":7,"size":[{"response":[1,2],"freq":[127,339]}]}}],"surrogates":[],"info":{"data":{"survived":[2,2,1,1,1,2,2,1,2,1,1,2,2,2,2,1,1,2,2,1,2,2,2,2,2,1,2,2,2,2,1,2,2,2,1,2,2,2,1,1,1,2,2,2,2,1,1,2,2,2,2,1,1,1,2,2,2,2,1,2,1,2,1,2,2,2,2,2,2,2,1,1,2,2,1,1,2,1,2,2,1,1,2,2,1,2,2,2,2,1,2,2,2,2,2,2,1,2,2,2,2,1,2,2,2,1,1,2,2,2,1,2,2,2,1,1,2,2,1,2,2,2,2,2,2,1,1,2,1,2,2,2,1,2,2,1,2,2,1,2,2,2,1,2,2,2,2,1,1,2,1,2,2,2,1,2,1,1,1,2,2,2,1,2,2,2,1,2,2,1,2,1,1,1,1,1,2,2,2,1,2,2,2,2,1,1,2,2,2,1,2,1,2,2,1,2,2,1,2,2,1,1,2,1,2,1,1,2,2,2,1,1,1,2,2,1,2,1,2,2,2,1,1,1,1,1,1,2,1,2,2,2,1,2,1,2,1,1,2,1,2,1,2,1,1,2,1,2,1,2,2,2,1,2,2,2,2,2,2,2,2,2,1,2,2,2,1,1,1,1,2,2,2,2,2,2,1,2,2,1,2,2,2,1,2,1,1,1,2,2,1,2,2,2,1,2,2,2,2,1,1,1,2,1,2,1,1,1,2,2,1,2,1,1,2,2,1,2,1,2,2,1,2,1,2,1,1,1,1,2,1,1,1,2,1,1,2,2,1,2,2,2,2,2,2,1,1,1,1,2,2,1,2,2,1,2,1,1,2,2,2,2,2,1,1,1,1,1,1,1,2,2,1,2,1,1,2,2,1,2,2,1,1,1,1,2,1,2,2,1,1,1,2,1,1,2,2,1,2,1,2,2,2,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,2,2,1,2,1,2,1,2,1,2,2,2,1,2,2,1,1,1,1,2,1,1,2,1,1,2,1,2,1,1,1,2,1,2,1,1,1,1,2,1,2,1,2,1,2,1,1,1,1,1,1,2,2,1,2,2,2,2,1,1,1,1,2,1,1,2,1,2,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,2,2,1,2,2,1,2,1,1,2,1,1,1,2,2,1,2,1,2,1,2,2,2,1,1,2,2,1,2,2,2,2,1,2,1,1,1,2,2,2,2,1,2,1,2,1,1,1,1,1,2,1,2,2,1,1,1,2,1,1,2,1,2,2,2,1,2,2,2,2,2,2,1,2,1,1,2,2,2,1,1,1,1,2,2,2,2,2,1,1,1,2,2,2,1,1,1,1,1,1,1,2,1,1,1,2,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,2,1,2,2,2,1,1,1,1,1,2,1,1,2,2,2,2,2,2,1,1,2,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,2,1,1,1,1,2,1,1,1,1,1,2,1,1,1,1,1,1,1,2,2,2,1,1,2,1,1,1,2,1,1,2,2,1,1,1,1,1,1,1,1,1,1,2,2,2,2,1,2,2,1,2,1,1,1,1,1,2,1,1,1,1,1,2,2,1,2,1,1,2,1,2,1,1,1,1,1,1,1,1,2,1,1,1,2,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,2,1,1,1,1,2,2,2,1,2,1,2,1,1,1,2,2,1,1,2,1,2,1,2,1,1,1,1,1,2,2,1,1,1,1,2,2,1,2,1,1,1,1,2,2,1,1,1,2,1,1,1,1,1,2,1,1,1,2,1,1,1,2,1,1,2,2,1,1,1,1,2,2,1,1,2,1,1,1,1,1,1,1,2,2,2,1,1,1,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1,2,2,1,1,2,2,1,1,1,1,1,2,1,2,1,1,1,2,1,2,2,2,2,2,2,1,2,2,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,2,1,2,2,1,2,1,1,1,1,2,2,2,2,2,1,2,2,1,2,2,2,1,1,2,2,2,2,1,1,1,1,1,2,2,1,1,2,2,1,1,2,1,1,2,1,1,1,2,1,1,1,1,1,2,2,2,2,2,2,1,1,1,1,1,2,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,2,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,2,2,2,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,2,1,1,1,1,2,1,1,1,2,2,1,1,2,1,2,1,2,1,1,1,2,1,1,2,1,1,1,1,1,1,2,1,2,2,2,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,2,1,1,1,2,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1],"pclass":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],"sex":[1,2,1,2,1,2,1,2,1,2,2,1,1,1,2,2,2,1,1,2,2,1,2,1,1,2,2,1,1,2,2,2,1,1,2,1,1,2,2,2,2,1,1,1,1,2,2,2,1,2,1,2,2,2,2,1,2,1,2,1,2,1,2,1,2,1,1,1,2,1,2,2,1,1,2,2,1,2,1,1,2,2,1,1,2,1,2,2,1,2,1,2,1,2,2,1,2,1,1,1,2,2,1,1,1,1,2,1,1,2,2,1,1,1,2,2,1,1,2,2,2,1,1,2,1,2,2,1,2,1,1,1,2,2,1,2,2,1,2,1,2,1,2,2,1,2,1,2,2,1,2,2,2,1,2,1,2,2,2,1,1,1,2,1,2,2,2,1,1,1,2,2,2,2,2,2,1,2,1,2,1,1,1,2,2,2,1,1,1,2,1,2,1,1,2,1,2,2,1,1,2,2,2,2,1,2,2,1,1,2,2,2,2,1,1,2,1,2,1,2,1,2,2,2,2,2,2,1,2,1,1,2,2,1,2,2,2,2,1,2,2,2,1,2,2,1,2,1,2,2,1,1,2,1,2,1,2,1,1,2,1,2,2,1,2,2,2,2,2,2,1,2,1,2,2,1,2,1,2,2,2,1,1,2,1,2,1,2,1,1,2,1,2,1,2,2,1,1,2,2,2,2,1,2,1,2,2,2,1,1,2,1,2,2,1,1,2,2,2,1,2,2,1,2,1,2,2,2,2,1,2,2,2,1,2,2,2,1,2,2,1,1,1,2,1,2,2,2,2,1,1,2,1,1,2,1,2,2,1,2,2,1,1,2,2,1,2,2,2,1,1,1,2,1,2,2,2,1,2,1,1,1,1,2,2,2,2,1,1,2,2,2,1,2,2,1,1,2,2,2,1,1,1,2,2,2,2,1,2,2,2,1,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2,2,2,1,2,1,1,1,2,1,1,2,2,2,1,1,2,2,1,2,2,1,2,2,2,1,2,1,2,1,2,2,2,2,1,2,1,1,1,2,1,2,2,2,1,2,2,1,1,2,1,1,1,1,2,2,2,2,1,1,2,2,2,1,2,2,2,2,2,2,1,1,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,1,1,2,1,2,2,2,1,1,1,2,2,1,1,2,2,2,1,1,2,1,2,2,2,1,1,1,1,2,1,2,1,2,2,2,2,2,1,2,1,1,2,1,2,1,2,2,1,2,1,1,1,2,1,2,1,1,1,1,2,1,2,2,2,2,1,1,2,2,2,1,1,2,2,1,2,2,1,2,1,2,2,2,2,2,2,2,2,1,2,1,1,1,1,1,1,2,2,2,1,2,2,2,1,2,2,2,2,2,2,1,2,2,1,1,2,2,1,2,2,1,2,2,1,1,1,1,1,1,2,2,2,1,1,1,2,2,2,2,2,2,2,2,2,2,2,1,2,1,1,2,1,2,1,1,2,2,2,2,1,2,2,1,1,1,2,2,2,2,1,2,2,2,1,2,2,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,2,2,2,2,2,2,2,2,1,2,2,1,2,2,2,2,1,2,1,2,2,2,1,2,2,2,2,2,2,2,1,2,1,2,2,2,1,2,1,2,2,2,2,2,1,2,2,2,2,2,2,1,1,1,2,2,2,2,1,2,2,2,2,2,2,2,2,1,2,2,2,2,2,1,2,2,2,2,2,1,1,2,2,2,1,2,2,2,2,2,2,1,1,2,2,2,1,2,2,2,2,1,1,2,2,1,2,2,2,2,2,2,2,1,1,2,2,2,1,2,2,2,2,2,1,1,2,2,2,1,2,2,1,1,1,1,2,1,1,1,1,2,2,1,2,1,2,2,2,2,1,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,1,2,2,2,1,2,1,2,1,2,2,2,1,1,2,2,2,2,2,2,2,1,2,2,2,2,2,1,1,2,2,2,2,1,2,2,2,1,2,1,2,1,1,2,1,2,2,2,1,2,2,2,1,2,2,2,2,2,2,2,1,1,1,1,2,2,1,2,2,2,2,1,1,2,1,2,2,2,2,2,1,2,2,2,2,1,2,2,2,1,2,2,1,2,2,2,2,1,1,2,2,2,1,2,1,2,1,1,2,1,2,1,1,1,2,2,1,1,1,1,2,2,2,2,2,2,2,2,1,2,2,1,2,1,2,2,2,2,2,2,2,1,1,2,1,1,2,1,1,1,2,2,1,1,2,1,2,2,2,1,2,2,1,1,2,1,1,2,2,2,2,2,1,2,2,2,1,2,2,2,2,1,1,1,1,2,1,2,2,2,2,1,2,2,2,1,1,2,2,1,1,2,2,1,1,1,2,2,2,2,2,1,2,2,2,2,2,1,1,2,2,2,2,2,2,2,2,1,1,1,2,1,2,2,2,1,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,1,1,2,1,2,1,2,1,2,2,1,2,1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,1,2,1,2,2,2,2,1,1,1,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,1,2,2,1,1,2,1,2,2,2,2,1,2,2,2,2,2,2,1,2,2,2,1,2,2,1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,1,2,2,2,2,2,2,2,2,2,1,1,2,1,1,2,2,2,1,2,1,2,2,2,2,2,1,2,2,1,2,2,1,2,2,2,2,2,2,1,2,2,2,1,2,2,2,2,2,2,2,2,2,1,2,2,2,1,1,2,2,2],"age":[29,0.9167,2,30,25,48,63,39,53,71,47,18,24,26,80,"NA",24,50,32,36,37,47,26,42,29,25,25,19,35,28,45,40,30,58,42,45,22,"NA",41,48,"NA",44,59,60,41,45,"NA",42,53,36,58,33,28,17,11,14,36,36,49,"NA",36,76,46,47,27,33,36,30,45,"NA","NA",27,26,22,"NA",47,39,37,64,55,"NA",70,36,64,39,38,51,27,33,31,27,31,17,53,4,54,50,27,48,48,49,39,23,38,54,36,"NA","NA","NA",36,30,24,28,23,19,64,60,30,"NA",50,43,"NA",22,60,48,"NA",37,35,47,35,22,45,24,49,"NA",71,53,19,38,58,23,45,46,25,25,48,49,"NA",45,35,40,27,"NA",24,55,52,42,"NA",55,16,44,51,42,35,35,38,"NA",35,38,50,49,46,50,32.5,58,41,"NA",42,45,"NA",39,49,30,35,"NA",42,55,16,51,29,21,30,58,15,30,16,"NA",19,18,24,46,54,36,28,"NA",65,44,33,37,30,55,47,37,31,23,58,19,64,39,"NA",22,65,28.5,"NA",45.5,23,29,22,18,17,30,52,47,56,38,"NA",22,"NA",43,31,45,"NA",33,46,36,33,55,54,33,13,18,21,61,48,"NA",24,"NA",35,30,34,40,35,50,39,56,28,56,56,24,"NA",18,24,23,6,45,40,57,"NA",32,62,54,43,52,"NA",62,67,63,61,48,18,52,39,48,"NA",49,17,39,"NA",31,40,61,47,35,64,60,60,54,21,55,31,57,45,50,27,50,21,51,21,"NA",31,"NA",62,36,30,28,30,18,25,34,36,57,18,23,36,28,51,32,19,28,1,4,12,36,34,19,23,26,42,27,24,15,60,40,20,25,36,25,42,42,0.8333,26,22,35,"NA",19,44,54,52,37,29,25,45,29,28,29,28,24,8,31,31,22,30,"NA",21,"NA",8,18,48,28,32,17,29,24,25,18,18,34,54,8,42,34,27,30,23,21,18,40,29,18,36,"NA",38,35,38,34,34,16,26,47,21,21,24,24,34,30,52,30,0.6667,24,44,6,28,62,30,7,43,45,24,24,49,48,55,24,32,21,18,20,23,36,54,50,44,29,21,42,63,60,33,17,42,24,47,24,22,32,23,34,24,22,"NA",35,45,57,"NA",31,26,30,"NA",1,3,25,22,17,"NA",34,36,24,61,50,42,57,"NA",1,31,24,"NA",30,40,32,30,46,13,41,19,39,48,70,27,54,39,16,62,32.5,14,2,3,36.5,26,19,28,20,29,39,22,"NA",23,29,28,"NA",50,19,"NA",41,21,19,43,32,34,30,27,2,8,33,36,34,30,28,23,0.8333,3,24,50,19,21,26,25,27,25,18,20,30,59,30,35,40,25,41,25,18.5,14,50,23,28,27,29,27,40,31,30,23,31,"NA",12,40,32.5,27,29,2,4,29,0.9167,5,36,33,66,"NA",31,"NA",26,24,42,13,16,35,16,25,20,18,30,26,40,0.8333,18,26,26,20,24,25,35,18,32,19,4,6,2,17,38,9,11,39,27,26,39,20,26,25,18,24,35,5,9,3,13,5,40,23,38,45,21,23,17,30,23,13,20,32,33,0.75,0.75,5,24,18,40,26,20,18,45,27,22,19,26,22,"NA",20,32,21,18,26,6,9,"NA","NA","NA",40,32,21,22,20,29,22,22,35,18.5,21,19,18,21,30,18,38,17,17,21,21,21,"NA","NA",28,24,16,37,28,24,21,32,29,26,18,20,18,24,36,24,31,31,22,30,70.5,43,35,27,19,30,9,3,36,59,19,17,44,17,22.5,45,22,19,30,29,0.3333,34,28,27,25,24,22,21,17,"NA","NA",36.5,36,30,16,1,0.1667,26,33,25,"NA","NA",22,36,19,17,42,43,"NA",32,19,30,24,23,33,65,24,23,22,18,16,45,"NA",39,17,15,47,5,"NA",40.5,40.5,"NA",18,"NA","NA","NA",26,"NA","NA",21,9,"NA",18,16,48,"NA","NA",25,"NA","NA",22,16,"NA",9,33,41,31,38,9,1,11,10,16,14,40,43,51,32,"NA",20,37,28,19,24,17,"NA","NA",28,24,20,23.5,41,26,21,45,"NA",25,"NA",11,"NA",27,"NA",18,26,23,22,28,28,"NA",2,22,43,28,27,"NA","NA",42,"NA",30,"NA",27,25,"NA",29,21,"NA",20,48,17,"NA","NA",34,26,22,33,31,29,4,1,49,33,19,27,"NA","NA","NA","NA",23,32,27,20,21,32,17,21,30,21,33,22,4,39,"NA",18.5,"NA","NA","NA","NA",34.5,44,"NA","NA","NA","NA","NA","NA",22,26,4,29,26,1,18,36,"NA",25,"NA",37,"NA","NA","NA",22,"NA",26,29,29,22,22,"NA","NA","NA","NA","NA",32,34.5,"NA","NA",36,39,24,25,45,36,30,20,"NA",28,"NA",30,26,"NA",20.5,27,51,23,32,"NA","NA","NA",24,22,"NA","NA","NA",29,"NA",30.5,"NA","NA",35,33,"NA","NA","NA","NA","NA","NA","NA","NA","NA","NA",15,35,"NA",24,19,"NA","NA","NA",55.5,"NA",21,"NA",24,21,28,"NA","NA",25,6,27,"NA","NA","NA","NA",34,"NA","NA","NA","NA","NA","NA","NA","NA",24,"NA","NA","NA","NA",18,22,15,1,20,19,33,"NA","NA","NA","NA",12,14,29,28,18,26,21,41,39,21,28.5,22,61,"NA","NA","NA","NA","NA","NA",23,"NA","NA","NA",22,"NA","NA",9,28,42,"NA",31,28,32,20,23,20,20,16,31,"NA",2,6,3,8,29,1,7,2,16,14,41,21,19,"NA",32,0.75,3,26,"NA","NA","NA",21,25,22,25,"NA","NA","NA","NA",24,28,19,"NA",25,18,32,"NA",17,24,"NA","NA","NA","NA",38,21,10,4,7,2,8,39,22,35,"NA","NA","NA",50,47,"NA","NA",2,18,41,"NA",50,16,"NA","NA","NA",25,"NA","NA","NA",38.5,"NA",14.5,"NA","NA","NA","NA","NA","NA","NA","NA","NA",24,21,39,"NA","NA","NA",1,24,4,25,20,24.5,"NA","NA","NA",29,"NA","NA","NA","NA",22,"NA",40,21,18,4,10,9,2,40,45,"NA","NA","NA","NA","NA",19,30,"NA",32,"NA",33,23,21,60.5,19,22,31,27,2,29,16,44,25,74,14,24,25,34,0.4167,"NA","NA","NA",16,"NA","NA","NA",32,"NA","NA",30.5,44,"NA",25,"NA",7,9,29,36,18,63,"NA",11.5,40.5,10,36,30,"NA",33,28,28,47,18,31,16,31,22,20,14,22,22,"NA","NA","NA",32.5,38,51,18,21,47,"NA","NA","NA",28.5,21,27,"NA",36,27,15,45.5,"NA","NA",14.5,"NA",26.5,27,29]},"fitted":{"(fitted)":[7,6,7,3,7,3,7,3,7,3,3,7,7,7,3,3,3,7,7,3,3,7,3,7,7,3,3,7,7,3,3,3,7,7,3,7,7,3,3,3,3,7,7,7,7,3,3,3,7,3,7,3,3,3,3,7,3,7,3,7,3,7,3,7,3,7,7,7,3,7,3,3,7,7,3,3,7,3,7,7,3,3,7,7,3,7,3,3,7,3,7,3,7,3,6,7,3,7,7,7,3,3,7,7,7,7,3,7,7,3,3,7,7,7,3,3,7,7,3,3,3,7,7,3,7,3,3,7,3,7,7,7,3,3,7,3,3,7,3,7,3,7,3,3,7,3,7,3,3,7,3,3,3,7,3,7,3,3,3,7,7,7,3,7,3,3,3,7,7,7,3,3,3,3,3,3,7,3,7,3,7,7,7,3,3,3,7,7,7,3,7,3,7,7,3,7,3,3,7,7,3,3,3,3,7,3,3,7,7,3,3,3,3,7,7,3,7,3,7,3,7,3,3,3,3,3,3,7,3,7,7,3,3,7,3,3,3,3,7,3,3,3,7,3,3,7,3,7,3,3,7,7,3,7,3,7,3,7,7,3,7,3,3,7,3,3,3,3,3,3,7,3,7,6,3,7,3,7,3,3,3,7,7,3,7,3,7,3,7,7,3,7,3,7,3,3,7,7,3,3,3,3,7,3,7,3,3,3,7,7,3,7,3,3,7,7,3,3,3,7,3,3,7,3,7,3,3,3,3,7,3,3,3,7,3,3,3,7,3,6,7,7,7,3,7,3,3,3,3,7,7,3,7,7,3,7,3,3,7,6,3,7,7,3,3,7,3,3,3,7,7,7,3,7,3,3,3,7,3,7,7,7,7,3,3,6,3,7,7,3,3,3,7,3,3,7,7,3,6,3,7,7,7,3,3,3,3,7,3,3,3,7,3,3,3,7,3,3,3,3,3,3,3,3,3,3,3,6,7,3,7,3,3,3,7,3,7,7,7,3,7,7,3,3,3,7,7,3,3,7,3,3,7,3,3,3,7,3,7,3,7,3,3,3,3,7,3,7,7,7,3,7,3,3,3,7,3,3,7,7,3,7,7,7,7,3,3,3,3,7,7,3,6,3,7,3,3,3,3,3,3,7,7,3,3,3,3,3,3,3,3,3,3,7,6,6,3,3,3,3,3,7,3,3,3,3,3,3,3,7,3,3,3,7,7,3,7,3,3,3,7,7,7,3,3,7,7,3,6,6,7,7,3,7,3,3,3,7,7,7,7,3,7,3,7,3,3,3,3,3,7,3,7,7,3,7,3,7,3,3,7,3,7,7,7,3,7,6,7,7,7,7,3,7,3,3,3,3,7,7,3,3,3,7,7,3,3,7,3,3,7,5,7,3,3,3,3,3,3,3,3,7,5,7,7,7,7,7,7,3,3,3,7,3,3,3,7,3,3,5,5,5,3,7,3,3,7,7,3,3,7,3,3,7,3,3,7,7,7,7,7,7,3,3,3,7,7,7,3,3,3,3,3,3,3,3,3,3,5,7,3,7,7,3,7,3,7,7,3,3,3,3,7,3,3,7,7,7,3,3,3,3,7,3,3,3,7,3,3,7,7,3,3,3,3,3,3,3,3,3,3,3,3,3,3,7,7,3,3,3,3,3,3,5,5,7,3,3,7,3,3,3,3,7,3,7,3,5,3,7,3,3,3,3,3,3,3,7,3,7,3,3,5,7,3,7,3,3,3,3,3,7,3,3,3,3,3,3,7,7,7,3,3,3,3,7,3,3,3,3,3,3,3,3,7,3,3,3,3,3,7,3,3,3,3,3,7,7,3,3,3,7,3,3,3,3,3,3,7,7,5,3,3,7,3,5,5,3,7,7,3,3,7,3,3,3,3,3,3,3,7,7,3,3,3,7,3,3,3,3,3,7,7,3,3,3,7,3,3,7,7,7,7,3,7,7,7,7,3,3,7,3,7,3,3,3,3,7,7,3,3,3,3,3,3,3,7,3,3,3,3,3,3,3,5,7,3,3,3,7,3,7,3,7,3,3,3,7,7,3,3,3,3,3,3,3,7,3,3,3,3,3,7,7,3,3,3,3,7,3,3,3,7,3,7,3,7,7,3,7,3,3,3,7,3,3,3,7,3,3,3,3,3,3,3,7,7,7,7,3,3,7,3,3,3,3,7,7,3,7,3,3,3,3,3,7,3,3,3,3,7,3,3,3,7,3,3,7,3,3,3,3,7,7,3,3,3,7,3,7,3,7,7,3,7,3,7,7,7,3,3,7,7,7,7,3,3,3,3,3,3,3,3,7,3,5,7,3,7,3,3,3,3,3,3,3,7,7,3,7,7,3,7,7,7,3,3,7,7,3,7,3,3,3,7,3,3,7,7,3,7,7,3,3,3,3,3,7,3,3,3,7,3,3,3,3,7,7,7,7,3,7,5,3,3,3,7,3,3,3,7,7,3,3,7,7,5,5,7,7,7,5,5,5,3,3,7,3,3,3,3,5,7,7,3,3,3,3,3,3,3,3,7,7,7,3,7,3,3,3,7,3,3,3,3,3,7,3,3,3,3,3,5,5,5,5,7,7,3,7,3,7,3,7,3,3,7,3,7,7,3,3,3,3,3,3,3,3,3,3,3,3,7,7,7,7,3,3,3,3,7,3,7,3,3,3,3,7,7,7,3,3,3,3,3,3,3,3,7,3,3,3,3,3,3,7,5,3,7,7,3,7,3,3,3,3,7,3,3,3,3,3,3,7,3,3,3,7,3,3,7,7,3,3,3,3,3,3,3,3,5,3,3,3,7,3,3,7,3,3,3,3,3,3,3,3,5,7,7,3,7,7,3,3,3,7,3,7,3,3,3,3,3,7,3,3,7,3,3,7,3,3,3,3,3,3,7,3,3,3,7,3,3,3,3,3,3,3,3,3,7,3,3,3,7,7,3,3,3],"(response)":[2,2,1,1,1,2,2,1,2,1,1,2,2,2,2,1,1,2,2,1,2,2,2,2,2,1,2,2,2,2,1,2,2,2,1,2,2,2,1,1,1,2,2,2,2,1,1,2,2,2,2,1,1,1,2,2,2,2,1,2,1,2,1,2,2,2,2,2,2,2,1,1,2,2,1,1,2,1,2,2,1,1,2,2,1,2,2,2,2,1,2,2,2,2,2,2,1,2,2,2,2,1,2,2,2,1,1,2,2,2,1,2,2,2,1,1,2,2,1,2,2,2,2,2,2,1,1,2,1,2,2,2,1,2,2,1,2,2,1,2,2,2,1,2,2,2,2,1,1,2,1,2,2,2,1,2,1,1,1,2,2,2,1,2,2,2,1,2,2,1,2,1,1,1,1,1,2,2,2,1,2,2,2,2,1,1,2,2,2,1,2,1,2,2,1,2,2,1,2,2,1,1,2,1,2,1,1,2,2,2,1,1,1,2,2,1,2,1,2,2,2,1,1,1,1,1,1,2,1,2,2,2,1,2,1,2,1,1,2,1,2,1,2,1,1,2,1,2,1,2,2,2,1,2,2,2,2,2,2,2,2,2,1,2,2,2,1,1,1,1,2,2,2,2,2,2,1,2,2,1,2,2,2,1,2,1,1,1,2,2,1,2,2,2,1,2,2,2,2,1,1,1,2,1,2,1,1,1,2,2,1,2,1,1,2,2,1,2,1,2,2,1,2,1,2,1,1,1,1,2,1,1,1,2,1,1,2,2,1,2,2,2,2,2,2,1,1,1,1,2,2,1,2,2,1,2,1,1,2,2,2,2,2,1,1,1,1,1,1,1,2,2,1,2,1,1,2,2,1,2,2,1,1,1,1,2,1,2,2,1,1,1,2,1,1,2,2,1,2,1,2,2,2,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,2,2,1,2,1,2,1,2,1,2,2,2,1,2,2,1,1,1,1,2,1,1,2,1,1,2,1,2,1,1,1,2,1,2,1,1,1,1,2,1,2,1,2,1,2,1,1,1,1,1,1,2,2,1,2,2,2,2,1,1,1,1,2,1,1,2,1,2,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,2,2,1,2,2,1,2,1,1,2,1,1,1,2,2,1,2,1,2,1,2,2,2,1,1,2,2,1,2,2,2,2,1,2,1,1,1,2,2,2,2,1,2,1,2,1,1,1,1,1,2,1,2,2,1,1,1,2,1,1,2,1,2,2,2,1,2,2,2,2,2,2,1,2,1,1,2,2,2,1,1,1,1,2,2,2,2,2,1,1,1,2,2,2,1,1,1,1,1,1,1,2,1,1,1,2,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,2,1,2,2,2,1,1,1,1,1,2,1,1,2,2,2,2,2,2,1,1,2,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,2,1,1,1,1,2,1,1,1,1,1,2,1,1,1,1,1,1,1,2,2,2,1,1,2,1,1,1,2,1,1,2,2,1,1,1,1,1,1,1,1,1,1,2,2,2,2,1,2,2,1,2,1,1,1,1,1,2,1,1,1,1,1,2,2,1,2,1,1,2,1,2,1,1,1,1,1,1,1,1,2,1,1,1,2,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,2,1,1,1,1,2,2,2,1,2,1,2,1,1,1,2,2,1,1,2,1,2,1,2,1,1,1,1,1,2,2,1,1,1,1,2,2,1,2,1,1,1,1,2,2,1,1,1,2,1,1,1,1,1,2,1,1,1,2,1,1,1,2,1,1,2,2,1,1,1,1,2,2,1,1,2,1,1,1,1,1,1,1,2,2,2,1,1,1,1,2,1,1,1,2,1,2,1,2,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1,2,2,1,1,2,2,1,1,1,1,1,2,1,2,1,1,1,2,1,2,2,2,2,2,2,1,2,2,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,2,1,2,2,1,2,1,1,1,1,2,2,2,2,2,1,2,2,1,2,2,2,1,1,2,2,2,2,1,1,1,1,1,2,2,1,1,2,2,1,1,2,1,1,2,1,1,1,2,1,1,1,1,1,2,2,2,2,2,2,1,1,1,1,1,2,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,2,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,2,2,2,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,2,1,1,1,1,2,1,1,1,2,2,1,1,2,1,2,1,2,1,1,1,2,1,1,2,1,1,1,1,1,1,2,1,2,2,2,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,2,1,1,1,2,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1]},"terms":"survived~pclass + sex + age","names":[],"info":{"method":"rpart"}},"description":" root","rule":"","var":4,"n":2195,"wt":1309,"dev":500,"yval":1,"complexity":0.424,"ncompete":2,"nsurrogate":0,"yval2":[[1,809,500,0.618,0.382,1]],"size":{"fitted":[],"size":[]}}
var hier = d3.hierarchy(titanic)
var width = 800;
var height = 600;
var nodeWidth = 10;
var color = d3.scaleOrdinal(d3.schemeCategory10);
// rearrange so that survived yes is green
// and no is red
color.range(
[color.range()[2]]
.concat([color.range()[3]])
.concat(color.range().splice(0,2))
.concat(color.range().splice(4,10))
)
color.domain(['2', '1'])
var svg = d3.select('#vis').append('svg')
.style('width',width + 20 + 20)
.style('height',height + 20 + 20)
.append('g')
.attr('transform','translate(20,20)');
// n will represent sum at each split
// so don't use hier.sum
// instead add value attribute
hier.each(function(d) {d.value = d.data.wt})
// caution will mutate the object
layout(hier, nodeWidth, 0.75)
// note, this will not follow traditional d3 call form
// if we were to make this official change this to svg.call
var nodes = drawNodes(hier, svg)
var links = drawLinks(nodes, svg)
// add mouseover that highlights with higher opacity
// this will highlight all children with same leaf name
svg.selectAll('.link').on('mouseover', function(d) {
d3.select(this).style('opacity', 0.8)
if(d.target.linkPaths) {
d.target.descendants().forEach(function(dd) {
if(dd.linkPaths){
dd.linkPaths.forEach(function(lp) {
var data = d3.select(lp).datum();
if(data.leaf == d.leaf) {
d3.select(lp).style('opacity', 0.8)
}
})
}
})
}
})
svg.selectAll('.link').on('mouseout', function(d) {
svg.selectAll('.link').style('opacity', 0.5)
})
function layout(hier, nodeWidth, nodeHeightRatio) {
nodeWidth = nodeWidth ? nodeWidth : 10;
nodeHeightRatio = nodeHeightRatio ? nodeHeightRatio : 0.66;
var nodeHeight = height * nodeHeightRatio;
// run treemap slice to get heights
// note, this will overwrite the x0,x1,y0,y1
d3.treemap()
.size([nodeWidth, nodeHeight])
.tile(d3.treemapSlice)(hier);
// record treemap heights and widths
// since partition will overwrite
hier.each(function(d) {
d.h = d.y1 - d.y0;
d.w = d.x1 - d.x0;
})
// now run partition with no size
// so will be in range [0,1]
d3.partition()(hier);
}
function drawNodes(hier, svg) {
var nodes = svg.selectAll('g.node')
.data(hier.descendants());
nodes = nodes.merge(
nodes.enter().append('g')
.attr('class','node')
);
nodes.attr('transform', function(d) {
return 'translate(' + d.y0 * width + ',' + d.x0 * height + ')'
});
nodes.append('rect')
.classed('rect-part', true);
nodes.append('text')
//.style('text-anchor','end')
.attr('dy','0.5em')
.text(function(d) { return d.data.description});
nodes.selectAll('rect.rect-part')
.style('fill', 'gray')//function(d) {return color(d.data.name)})
.style('stroke', 'white')
//.transition()
//.duration(duration)
//.delay(delay)
.attr('y', function(d) {
return ((d.x1-d.x0)*height-d.h)/2;
})
.attr('width', function(d) { return nodeWidth; })
.attr('height', function(d) {
return d.h;
});
nodes.selectAll('text')
.attr('y', function(d) {
if(d.height > 0) {
return ((d.x1-d.x0)*height-d.h)/2;
}
return (d.x1-d.x0)*height/2;
})
.attr('x', function(d) {
if(d.height > 0) {
return nodeWidth / 2
}
return nodeWidth
})
.attr('dy', function(d) {
if(d.height > 0) {
return '-0.15em'
}
return '0.25em'
})
.style('text-anchor', function(d) {
if(d.height > 0) {
return 'middle'
}
return 'start'
})
return nodes;
}
function drawLinks(nodes, svg) {
function stackSource(x) {
var xobj = {}
var sum = x.data.wt
x.children.forEach(function(d) {
// sum by response by using leaf data
var leafdat = d.leaves().map(function(lf) {
return lf.data.size.size[0]
})
var sizes = d3.zip(
d3.merge(leafdat.map(function(d){return d.response})),
d3.merge(leafdat.map(function(d){return d.freq}))
)
var sumsResponse = d3.nest()
.key(function(d){return d[0]})
.rollup(function(d){
return d3.sum(d.map(function(dd){return dd[1]}))
})
.entries(sizes)
sumsResponse.forEach(function(dd) {
xobj[d.data.id + '~' + dd.key] = dd.value/sum;
})
})
return d3.stack().keys(Object.keys(xobj))([xobj]);
}
function stackTarget(x) {
// sum by response by using leaf data
var leafdat = x.leaves().map(function(d) {
return d.data.size.size[0]
})
var sizes = d3.zip(
d3.merge(leafdat.map(function(d){return d.response})),
d3.merge(leafdat.map(function(d){return d.freq}))
)
var sumsResponse = d3.nest()
.key(function(d){return d[0]})
.rollup(function(d){
return d3.sum(d.map(function(dd){return dd[1]}))
})
.entries(sizes)
var xobj = {};
var sum = d3.sum(sumsResponse.map(function(d){
return d.value
}))
sumsResponse.forEach(function(d) {
xobj[d.key] = d.value/sum;
})
return d3.stack().keys(Object.keys(xobj))([xobj]);
}
nodes.each(function(node) {
if(node.height == 0) {return}
// empty array to store links on each node
node.linkPaths = node.linkPaths ? node.linkPaths : [];
function customLine(pts) {
var ld = d3.linkHorizontal()
.source(function(d){return d[0]})
.target(function(d){return d[1]})
.x(function(d){return d[0]})
.y(function(d){return d[1]});
return [
ld([pts[0],pts[1]]),
pts[1] + ',' + pts[2],
ld([pts[2],pts[3]]).slice(1)
].join('L');
}
var st1 = stackSource(node);
st1.forEach(function(d) {
var childname = d.key.split('~')[0]
var leafname = d.key.split('~')[1]
var child = node.children.filter(function(ch) {
return ch.data.id == childname
})[0]
var st = stackTarget(child).filter(function(d) {
return d.key === leafname
})[0];
var link = svg.append('path')
.classed('link', true)
.style('opacity', 0.000001)
link.datum({
source: node,
target: child,
leaf: leafname
})
link.attr('d',customLine([
[node.y0 * width + nodeWidth, ((node.x0 * height) + ((node.x1-node.x0)*height-node.h)/2 ) + d[0][0]*node.h],
[child.y0 * width, ((child.x0 * height) + ((child.x1-child.x0)*height-child.h)/2 ) + st[0][0]*child.h],
[child.y0 * width, ((child.x0 * height) + ((child.x1-child.x0)*height-child.h)/2 ) + st[0][1]*child.h],
[node.y0 * width + nodeWidth, ((node.x0 * height) + ((node.x1-node.x0)*height-node.h)/2 ) + d[0][1]*node.h],
]));
link
.style('stroke', 'white')
.style('fill', color(leafname));
link
.transition()
//.duration(500)
//.delay(duration+delay)
.style('opacity', 0.5);
node.linkPaths = node.linkPaths.concat(link.node());
})
})
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment