Skip to content

Instantly share code, notes, and snippets.

@mimno
Last active June 7, 2016 15:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mimno/93337b5bd77d4217d0869b5b58c45243 to your computer and use it in GitHub Desktop.
Save mimno/93337b5bd77d4217d0869b5b58c45243 to your computer and use it in GitHub Desktop.
Divided Lines from a Scale

This is a simplified version of Elijah Meeks' Divided Line II block that uses a d3 threshold scale instead of a custom parameters function. The dividedLine function takes an aesthetic function as a parameter, which unpacks an attribute of the point object (y, in this case) and applies the scale.

<html>
<head>
<title>Divided Lines from a scale</title>
<meta charset="utf-8" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.16/d3.min.js"></script>
</head>
<style>
svg {
height: 500px;
width: 500px;
border: 1px solid gray;
}
path {
fill: none;
stroke-width: 5;
}
</style>
<body>
<div id="viz">
<svg class="main">
</svg>
</div>
</body>
<footer>
<script>
function dividedLine(aesthetic, points) {
var currentAesthetic = aesthetic(points[0]);
var currentPointsArray = [];
dividedLinesData = [{ aesthetic: currentAesthetic, points: currentPointsArray }];
points.forEach(function (point, i) {
var newAesthetic = aesthetic(point)
if (newAesthetic === currentAesthetic) {
currentPointsArray.push(point);
}
else {
var lastPoint = currentPointsArray[currentPointsArray.length - 1];
var pointA = lastPoint;
var pointB = point;
for (var x = 0; x < 10; x++) {
var findPoints = simpleSearchFunction(pointA, pointB, currentAesthetic, aesthetic);
pointA = findPoints[0];
pointB = findPoints[1];
}
currentPointsArray.push(pointB);
currentPointsArray = [pointB, point];
dividedLinesData.push({ aesthetic: newAesthetic, points: currentPointsArray});
currentAesthetic = newAesthetic;
}
});
return dividedLinesData.filter(function (d) {return d.points.length > 1});
}
function simpleSearchFunction(pointA, pointB, current, aesthetic) {
var pointCX = (pointA.x + pointB.x) / 2;
var pointCY = (pointA.y + pointB.y) / 2;
if (aesthetic({x: pointCX, y: pointCY}) === current) {
return [{x: pointCX, y: pointCY}, pointB];
}
return [pointA, {x: pointCX, y: pointCY}];
}
function randomLineGenerator(width, height, points) {
var pointDataSet = []
var curY = 0.5
for (var x = 0; x< points; x++) {
curY += Math.random() * 0.3 - 0.15;
curY = Math.max(curY, 0.05)
curY = Math.min(curY, 0.95)
pointDataSet.push({ x: x / points * width, y: curY * height })
}
return pointDataSet
}
var lineData = randomLineGenerator(500,500,100);
var meanY = d3.mean(lineData, function (d) { return d.y; });
var meanThreshold = d3.scale.threshold().domain([ meanY ]).range(["#ef8a62", "#67a9cf"]);
var yValue = function (d) { return meanThreshold(d.y); }
var line = d3.svg.line()
.x(function (d) {return d.x})
.y(function (d) {return d.y})
.interpolate("basis")
var dLineData = dividedLine(yValue, lineData);
var color = d3.scale.category20()
d3.select("svg")
.selectAll("path.segment")
.data(dLineData)
.enter()
.append("path")
.attr("d", function (d) { return line(d.points); } )
.style("stroke", function (d) { return d.aesthetic; } );
</script>
</footer>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment