block by emeeks 38b7f4552e63c88f2c3afe76efda0b58

Boole Hasse Diagram

Full Screen

A Hasse diagram drawn using the new D3v4 force-layout by specifying a d3.forceY constraint based on the distance from an arbitrary root node, in this case “FALSE”.

index.html

<html>
<head>
  <title>d3v4 Boole Hasse Diagram</title>
  <meta charset="utf-8" />
<script src="https://d3js.org/d3.v4.0.0-alpha.33.min.js"></script>
</head>
<style>
  svg {
    height: 500px;
    width: 500px;
    border: 1px solid gray;
  }
</style>
<body>

<div id="viz">
  <svg class="main">
  </svg>
</div>
</body>
  <footer>
<script>

d3.csv("hasse_boole.csv",function(error,data) {createNetwork(data)});

function onlyUnique(value, index, self) {
  return self.indexOf(value) === index;
}

function createNetwork(data) {

  var edges = data;
  var nodes = [];
  var nodeHash = {};
  edges.forEach(function (d) {
    if (!nodeHash[d.source]) {
      var newNode = {id: d.source}
      nodes.push(newNode)
      nodeHash[d.source] = newNode;
    }
    if (!nodeHash[d.target]) {
      var newNode = {id: d.target}
      nodes.push(newNode)
      nodeHash[d.target] = newNode;
    }
    d.source = nodeHash[d.source];
    d.target = nodeHash[d.target];
  })

var rootNode = nodes.filter(function (d) {return d.id === "FALSE"})[0]

rootNode.row = 0;

friendlyBFS(rootNode);

//Easy to do because this is a simple DAG
function friendlyBFS(node) {
  var targets = edges.filter(function (d) {return d.source === node}).map(function (d) {return d.target});
  targets.forEach(function (d) {
    d.row = node.row + 1;
    friendlyBFS(d)
  })
}


var networkCenter = d3.forceCenter().x(250).y(250);
var manyBody = d3.forceManyBody().strength(-1000)
var linkForce = d3.forceLink(edges).id(function (d) {return d.id}).distance(30).iterations(1)


//Generic gravity for the X position
var forceX = d3.forceX(function (d) {return 250})
    .strength(0.05)

//strong y positioning based on row
var forceY = d3.forceY(function (d) {return d.row * 50})
    .strength(0.5)

  var force = d3.forceSimulation(nodes)
    .force("charge", manyBody)
    .force("link", linkForce)
    .force("center", networkCenter)
    .force("x", forceX)
    .force("y", forceY)
    .force("collide", function (d) {return 50})
    .on("tick", updateNetwork);

  var edgeEnter = d3.select("svg.main").selectAll("g.edge")
  .data(edges)
  .enter()
  .append("g")
  .attr("class", "edge");

  edgeEnter
  .append("line")
  .style("stroke-width", function (d) {return d.border ? "3px" : "1px"})
  .style("stroke", "black")
  .style("pointer-events", "none");

  var nodeEnter = d3.select("svg.main").selectAll("g.node")
  .data(nodes, function (d) {return d.id})
  .enter()
  .append("g")
  .attr("class", "node")

  nodeEnter.append("ellipse")
  .attr("rx", 28)
  .attr("ry", 14)
  .style("fill", "white")
  .style("stroke", "black")
  .style("stroke-width", function (d) {return d.border ? "3px" : "1px"})

  nodeEnter.append("text")
  .style("text-anchor", "middle")
  .attr("y", 3)
  .style("stroke-width", "1px")
  .style("stroke-opacity", 0.75)
  .style("stroke", "white")
  .style("font-size", "8px")
  .text(function (d) {return d.id})
  .style("pointer-events", "none")

  nodeEnter.append("text")
  .style("text-anchor", "middle")
  .attr("y", 3)
  .style("font-size", "8px")
  .text(function (d) {return d.id})
  .style("pointer-events", "none")

  function updateNetwork(e) {
    d3.select("svg.main").selectAll("line")
    .attr("x1", function (d) {return d.source.x})
    .attr("y1", function (d) {return d.source.y})
    .attr("x2", function (d) {return d.target.x})
    .attr("y2", function (d) {return d.target.y});

    d3.select("svg.main").selectAll("g.node")
      .attr("transform", function (d) {return "translate(" + d.x + "," + d.y + ")"});

  }

}
</script>
  </footer>

</html>

hasse_boole.csv

source,target
"FALSE","p&q"
"FALSE","p&¬q"
"FALSE","¬p&q"
"FALSE","¬p&¬q"
"p&q","p"
"p&q","q"
"p&q","p IFF q"
"p&¬q","p"
"p&¬q","p IFF ¬q"
"p&¬q","(¬q)"
"¬p&q","p IFF ¬q"
"¬p&q","q"
"¬p&q","(¬p)"
"¬p&¬q","p IFF q"
"¬p&¬q","(¬q)"
"¬p&¬q","(¬p)"
"p","pvq"
"p","q IMPLIES p"
"q","pvq"
"q","p IMPLIES q"
"p IFF q","q IMPLIES p"
"p IFF q","p IMPLIES q"
"p IFF ¬q","pvq"
"p IFF ¬q","¬pv¬q"
"(¬q)","q IMPLIES p"
"(¬q)","¬pv¬q"
"(¬p)","p IMPLIES q"
"(¬p)","¬pv¬q"
"pvq","TRUE"
"q IMPLIES p","TRUE"
"p IMPLIES q","TRUE"
"¬pv¬q","TRUE"