Skip to content

Instantly share code, notes, and snippets.

@pablomm
Last active August 3, 2018 12:16
Show Gist options
  • Save pablomm/4307ef5bcc96df4041d6a8e3d297f37e to your computer and use it in GitHub Desktop.
Save pablomm/4307ef5bcc96df4041d6a8e3d297f37e to your computer and use it in GitHub Desktop.
Cantor distribution
<!DOCTYPE html>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="style.css">
<body>
<button type="button" onclick="animation()">Animation</button>
<div id="chart">
<div class="svg-container"></div>
</div>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="script.js"></script>
</body>
/*
* Zoomable graph of the cantor's distribution function
* Modificated version of Matjaz Zeleznik code snippet
* https://jsfiddle.net/matjazzeleznik/hara70wa/
* Uses d3.js v3
*/
var chartBody;
var clip;
var line;
var x;
var y;
var zoom;
var make_x_axis;
var make_y_axis;
var xAxis;
var yAxis;
var area;
var areaPath;
var width;
var height;
var margin;
var epsilon = .05;
var data = [];
/**
* Generates the points needed to interpolate the cantor's function,
* and stores them in the global variable 'data'
* @param {int} Number of iterations
*/
function CantorDistibution(n) {
data = [{ x: 0, y: 0 }];
CantorStep(1, n, 1./3., 0.5, 0,0);
data.push({ x: 1, y: 1 });
}
function CantorStep(i,n, dx, dy, bx, by){
if(i > n) return;
CantorStep(i+1, n, dx/3., dy/2., bx, by);
data.push({ x: bx + dx, y: by + dy});
data.push({ x: bx + 2*dx, y: by + dy});
CantorStep(i+1, n, dx/3., dy/2., bx + 2*dx, by + dy);
}
var counter;
function initAll() {
CantorDistibution(12);
initGraph();
plotData();
}
function animation() {
/* Clears all timeouts */
var id = window.setTimeout(function() {}, 0);
while (id--) {
window.clearTimeout(id);
}
counter = 0;
animationTimer();
}
function animationTimer() {
counter++;
CantorDistibution(counter);
plotData();
if(counter < 12) {
setTimeout(animationTimer, 1000);
}
}
/**
* Plots the axis and an empty chart
* in the html element with id #chart
*/
function initGraph() {
margin = {
top: 0,
right: 20,
bottom: 20,
left: 45
};
width = 600 - margin.left - margin.right;
height = 400 - margin.top - margin.bottom;
x = d3.scale.linear()
.domain(d3.extent(data, function(d) {
return d.x;
}))
.range([0, width]);
y = d3.scale.linear()
.domain([0, 1. + epsilon])
.range([height, 0]);
line = d3.svg.line()
.interpolate('linear')
.x(function(d) {
return x(d.x);
})
.y(function(d) {
return y(d.y);
});
zoom = d3.behavior.zoom()
.x(x)
.y(y)
.on("zoom", zoomed);
svg = d3.select('#chart > .svg-container')
.append("svg:svg")
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 600 400")
.classed("svg-content-responsive", true)
.append("svg:g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom);
svg.append("svg:rect")
.attr("width", width)
.attr("height", height)
.attr("class", "plot");
make_x_axis = function() {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5);
};
make_y_axis = function() {
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5);
};
xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5);
svg.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0, " + height + ")")
.call(xAxis);
yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("x", -5)
.attr("dy", ".71em")
.style("text-anchor", "end");
svg.append("g")
.attr("class", "x grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat(""));
svg.append("g")
.attr("class", "y grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat(""));
clip = svg.append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height);
chartBody = svg.append("g")
.attr("clip-path", "url(#clip)");
}
function zoomed() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.select(".x.grid")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat(""));
svg.select(".y.grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat(""));
svg.select(".line")
.attr("class", "line")
.attr("d", line);
svg.select("path.area").attr("d", area);
}
function plotData() {
svg.selectAll("path").remove();
chartBody.append("svg:path")
.datum(data)
.attr("class", "line")
.attr("d", line);
area = d3.svg.area()
.interpolate('linear')
.x(function(d) {
return x(d.x);
})
.y0(height)
.y1(function(d) {
return y(d.y);
});
// Add the filled area
areaPath = chartBody.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area);
}
initAll();
svg {
font-size: 11px;
}
.plot {
fill: #FFF;
}
.tick > text{
fill: #414141;
font-weight: bold;
}
.area {
fill: lightsteelblue;
stroke-width: 0;
opacity:0.5;
}
.grid .tick {
stroke: lightgrey;
opacity: 0.7;
}
.grid path {
stroke-width: 0;
}
.axis path, .axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
.svg-content-responsive {
display: inline-block;
position: absolute;
top: 10px;
left: 0;
}
.svg-container {
display: inline-block;
position: relative;
width: 100%;
padding-bottom: 75%;
vertical-align: top;
overflow: hidden;
}
#chart {
width: 700px;
height: 512px;
}
@pablomm
Copy link
Author

pablomm commented Jan 3, 2018

Result of the code snippet on bl.ocks.org

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment