A Monte Carlo approximation of the area of overlap between two circles, inspired by this 538 riddler question. Sample random points in a rectangle and see which circle(s) they fall into. If "both" is more than half of "left" or "right", chooose the middle slices.
Last active
July 14, 2017 13:53
-
-
Save mimno/d6b34ad78b8038de05c7073c76aa438c to your computer and use it in GitHub Desktop.
Monte Carlo sampling for 538 riddler (pizza slices)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'> | |
<script src="http://d3js.org/d3.v4.min.js" charset="utf-8"></script> | |
<style>body { font-family: "Open Sans"; margin: 30px; } div#float { float: right; width: 20%; } | |
svg { background-color: #eee; } | |
</style> | |
</head> | |
<body> | |
<h3>Which pizza slice?</h3> | |
<div id="float">A Monte Carlo approximation of the area of overlap between two circles, inspired by <a href="https://fivethirtyeight.com/features/can-you-eat-more-pizza-than-your-siblings/">this 538 riddler question</a>. Sample random points in a rectangle and see which circle(s) they fall into. If "both" is more than half of "left" or "right", chooose the middle slices.</div> | |
<div><button id="sampleButton">Sample</button> <input type="text" id="numPoints" value="1000" /> points.</div> | |
<svg height="400" width="600"></svg> | |
<div> | |
<script> | |
var svg = d3.select("svg"); | |
var height = svg.attr("height"); | |
var width = svg.attr("width"); | |
var categories = ["left", "right", "both", "neither"]; | |
var xScale = d3.scaleLinear().domain([-0.3,3.3]).range([0, width]); | |
var yScale = d3.scaleLinear().domain([-0.3,2.3]).range([height, 0]); | |
var colorScale = d3.scaleOrdinal(d3.schemeCategory10).domain(categories); | |
var texts = svg.selectAll("text").data(categories).enter().append("text") | |
.attr("x", 5) | |
.attr("y", function (d, i) { return 20 + 20 * i; }); | |
var randomPoint = function () { | |
return { x: Math.random() * 3, y: Math.random() * 2 }; | |
}; | |
var insideLeftCircle = function (point) { | |
var x = point.x - 1; | |
var y = point.y - 1; | |
return x * x + y * y < 1.0; | |
}; | |
var insideRightCircle = function (point) { | |
var x = point.x - 2; | |
var y = point.y - 1; | |
return x * x + y * y < 1.0; | |
}; | |
var counts = { "left": 0, "right": 0, "both": 0, "neither": 0 }; | |
function sample() { | |
var numPoints = d3.select("#numPoints").property("value"); | |
for (var i = 0; i < numPoints; i++) { | |
var point = randomPoint(); | |
var inLeft = insideLeftCircle(point); | |
var inRight = insideRightCircle(point); | |
var hit = "neither"; | |
if (inLeft && inRight) { hit = "both"; } | |
else if (inLeft) { hit = "left"; } | |
else if (inRight) { hit = "right" } | |
counts[hit] += 1; | |
svg.append("circle") | |
.attr("cx", xScale(point.x)) | |
.attr("cy", yScale(point.y)) | |
.attr("r", 2) | |
.style("opacity", 0.25) | |
.style("fill", colorScale(hit)); | |
} | |
texts.text(function (d) { return d + ": " + counts[d]; }); | |
} | |
d3.select("#sampleButton").on("click", sample); | |
</script> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment