Skip to content

Instantly share code, notes, and snippets.

@theredpea
Last active January 14, 2018 17:37
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 theredpea/116f91986d20f4eb505224f00e56cd86 to your computer and use it in GitHub Desktop.
Save theredpea/116f91986d20f4eb505224f00e56cd86 to your computer and use it in GitHub Desktop.
nate probability complements demo

http://www-math.bgsu.edu/~albert/m115/probability/add_probs.html The complement rule (for computing probabilities of "not" events) Let's return to our lottery example. What if you're interested in the probability that the winning number does not have the same two digits. The rule for "not" events is called the complement rule:

Probability("not" an event) = 1 - Probability(event)

In this case, we can write

Probability(not same digits) = 1 - Probability(same digits)

We have already found the probability that the winning number has the same two digits, so the probability of interest is

Probability(not same digits) = 1 - 10/100 = 90/100

<!DOCTYPE html>
<html>
<head>
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
<!-- <link rel="stylesheet" type="text/css" href="index.css"/> -->
<style>
html,body,.content{
height:100%;
width:100%;
margin:0;
}
svg{
/* To fit better in a block */
margin-top: -3em;
}
/* from https://bl.ocks.org/mbostock/raw/3887235/e8f21e130ddc82f9f47d37d0b9d6345049dfd0f2/ */
text {
transition:all 0.5s linear;
font-family: 'Roboto', sans-serif;
font-size:3em;
text-anchor: middle;
}
.arc text {
font-size: 10px
}
.arc path {
/* animation: * ease-in-out; */
transition:fill-opacity 0.5s linear, stroke-width 0.5s linear;
/* ease-in-out; */
stroke: #fff;
stroke-width: 5px;
}
.arc.happen path{
fill: rgb(36, 36, 36);
}
.arc.not-happen path{
fill-opacity:1;
fill:rgb(224, 224, 224);
}
.together .arc.not-happen path {
fill-opacity:0;
}
.together .arc path {
stroke-width:2px;
}
.sum-line {
stroke-width: 10px;
stroke: #d5d5d5;
stroke-linecap: round;
}
.sum-line.button {
transition:fill 0.5s ease-in-out;
fill: #d5d5d5;
stroke: white;
stroke-width:5px;
}
.together .sum-line.button {
fill: black;
}
.together .pie-label text {
font-size:2em;
}
.together-pie-label-add {
font-size:12px;
fill:white;
}
</style>
<!-- Start by following this example -->
<!-- https://bl.ocks.org/mbostock/3887235 -->
<!-- Lets not worry about require and etc now -->
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<svg width="960" height="500"></svg>
<script >
// Just to satisfy JSHint
var d3 = window.d3 || {};
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
radius = Math.min(width, height) / 4;
var defs = svg.append('defs');
var together_pie_group_label_clip_id = 'together_pie_group_label_clip';
var together_pie_group_label_clip = defs
.append('clipPath')
.attr('id', 'together_pie_group_label_clip');
var pie = d3.pie()
.sort(null)
.value(function (d) { return d.prob; });
// https://developer.mozilla.org/en-US/docs/Web/Events/wheel
// https://github.com/d3/d3-selection/blob/master/README.md#selection_on
//One scroll twirl is about 10 events, each which do 100
//So ten scrolls to get to a full wheel:
// 10000 was too much
var scroll_range = 10000 / 4;
var arc_path = d3.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var get_prob_data = function (prob_options, non_prob_options) {
non_prob_options = non_prob_options || {};
//Returns two slicse of pie
return [
{
prob: prob_options.prob,
event: prob_options.event,
is_happen: false
},
{
prob: (1 - prob_options.prob),
event: non_prob_options.event || 'not ' + prob_options.event,
/* THe second slice, which will dominate the horizontal left of the pie
should represent the first of the 2 pies, which is on the left;
so that when the pie group labels come together, the labels
position relative to each other: 36% + 64%
correspond to the way the pie slices fit together, 36% arc on the *left* of the circle/pie; and 64% on the *right*
*/
is_happen: true
}]
};
var y_point = scroll_range / 2;
/* LINES BEFORE BUTTONS*/
var sum_line_label_line = svg
.append('line')
.attr('class', 'sum-line label');
var sum_line_pie_line = svg
.append('line')
.attr('class', 'sum-line pie')
.attr('y1', height / 2 + radius)
.attr('y2', height / 2 + radius);
var button_radius = 20;
var sum_line_pie_button = svg
.append('circle')
.attr('class', 'sum-line pie button')
.attr('cx', width / 2)
.attr('cy', height / 2 + radius)
.attr('r', 20);
var sum_line_label_button = svg
.append('circle')
.attr('class', 'sum-line label button')
.attr('cx', width / 2)
.attr('r', button_radius);
/*
var sum_line_label_close_button = svg
.append('circle')
.attr('class', 'sum-line pie close button')
.attr('cx', width / 2)
.attr('cy', height / 2 - 100)
.attr('r', button_radius);
*/
// /Not expected to be passed, so I won't call it func
var original_sum_lines = function () {
sum_line_label_button
.transition()
.ease(d3.easeCircleOut)
.duration(750)
.attr('cy', height / 2 - 40);
sum_line_label_line
.transition()
.ease(d3.easeCircleOut)
.duration(750)
.attr('y1', height / 2 - 40) //radius*0.5 )
.attr('y2', height / 2 - 40)//radius*0.5);
.attr('x1', width / 4 + 60) //*1.1)
.attr('x2', 3 * width / 4 - 60) // *1.1)
sum_line_pie_line
.transition()
.ease(d3.easeCircleOut)
.duration(750)
.attr('x1', width / 4 + radius) //*1.1)
.attr('x2', 3 * width / 4 - radius) // *1.1)
}
original_sum_lines();
// /Not expected to be passed, so I won't call it func
var together_sum_lines = function () {
sum_line_label_button
.transition()
// .delay(500)
.ease(d3.easeCircleOut)
.duration(750)
.attr('cy', height / 2 - radius * 0.85);
sum_line_label_line
.transition()
.ease(d3.easeCircleOut)
// .delay(500)
.duration(750)//radius*0.5);
.attr('y1', height / 2 - 100) //radius*0.5 )
.attr('y2', height / 2 - 100)
.attr('x1', width / 2) //*1.1)
.attr('x2', width / 2) // *1.1);
sum_line_pie_line
.transition()
.ease(d3.easeCircleOut)
.duration(750)//radius*0.5);
.attr('x1', width / 2) //*1.1)
.attr('x2', width / 2) // *1.1)
}
/*
// d3.select(sum_line_pie_button)
var button_size_func = function (button_Selection, new_radius) {
return function () {
button_Selection
.transition()
.ease(d3.easeCircleOut)
.duration(750)
.attr('r', new_radius);
}
}
sum_line_label_button
.on('mouseover', button_size_func(sum_line_label_button, button_radius * 1.5))
.on('mouseout', button_size_func(sum_line_label_button, button_radius))
sum_line_pie_button
.on('mouseover', button_size_func(sum_line_pie_button, button_radius * 1.5))
.on('mouseout', button_size_func(sum_line_pie_button, button_radius))
*/
var original_pie_translate_func = function (d, i) {
return "translate(" + (2 * i + 1) * width / 4 + "," + 3 * height / 4 + ")";
}
var together_pie_translate_func = function (d, i) {
//index doesnt matter, both pies move to the same point in the
//horizontal center point between the circles' centers
return "translate(" + width / 2 + "," + 3 * height / 4 + ")";
};
var are_together = false;
var pie_translate_func = function (transform_func) {
return function () {
return svg
.classed('together', are_together)
.selectAll('.prob-pie')
.transition()
.ease(d3.easeCircleOut)
.duration(750)
.attr("transform", transform_func);
}
};
// var prob_text_groups = pie_groups.selectAll('.text');
// var prob_text_groups = prob_text_groups
// .enter()
var pie_text_format = d3.format('.0%');
var text_adjust = function () {
/* TODO: Both numbers tween to 100%*/
d3.selectAll('.pie-label text')
.transition()
.ease(d3.easeCircleOut)
.duration(750)
/*
.tween('text', function (d) {
var from = are_together ? pie_text_val(d) : 1;
var to = are_together ? 1 : pie_text_val(d);
var i = d3.interpolate(from, to);
var node = this;
return function (t) {
node.textContent = pie_text_format(i(t));
};
});
*/
}
var toggle_together_func = function (d, i) {
if (are_together) {
are_together = false;
draw_pie();
text_adjust();
original_sum_lines();
original_pie_group_labels();
return pie_translate_func(original_pie_translate_func)();//(d, i);
} else {
are_together = true;
text_adjust();
together_sum_lines();
together_pie_group_labels();
return pie_translate_func(together_pie_translate_func)();//(d, i)
}
// .on('end', function(){
// });
};
/*
sum_line_label_close_button
.on('click', function (d, i) {
if (!are_together) {
return;
}
});
*/
// .attr({
// x1: function(){ return 20; },
// y1: "100",
// x2: "100",
// y2: "20",
// });
svg.on('wheel', function (data, index) {
d3.event.preventDefault();
// console.log(index);
// WheelEvent {isTrusted: true, deltaX: -0, deltaY: 100, deltaZ: 0, deltaMode: 0, …}
// console.log(d3.event);
y_point += d3.event.deltaY;
y_point = Math.min(y_point, scroll_range);
y_point = Math.max(y_point, 0);
draw_pie();
});
var get_scroll_data = function () {
return get_prob_data({ prob: y_point / scroll_range, event: 'heads' }, { event: 'tails' });
}
var tween_each_arc = function (pie_data) {
return function (d, i) {
var new_slice = pie_data[i];
var endAngle_interpolate = d3.interpolate(d.endAngle, new_slice.endAngle);
var startAngle_interpolate = d3.interpolate(d.startAngle, new_slice.startAngle);
return function (t) {
d.endAngle = endAngle_interpolate(t);
d.startAngle = startAngle_interpolate(t);
return arc_path(d);
};
}
};
var get_inverse_prob_data = function (prob_data) {
return prob_data.map(function (prob_options) {
return {
prob: prob_options.prob,
event: prob_options.event,
is_happen: !prob_options.is_happen
};
});
}
var get_scroll_pie_data = function () {
//DATA:
//==========
var data = get_scroll_data();
//inverse the second based on first
var inverse_data = get_inverse_prob_data(data);
//PIES:
//==========
//apply pie to both
var pie_data = pie(data);
var pie_inverse_data = pie(inverse_data);
//Return the happens case, then the inverse case:
return [pie_data, pie_inverse_data];
}
var pie_groups = svg.selectAll('g.prob-pie')
.data(get_scroll_pie_data());
pie_groups = pie_groups
.enter()
.append('g')
.attr('class', 'prob-pie')
.attr("transform", original_pie_translate_func);
var pie_text_val = function (d) {
var is_happening_slices = d.filter(function (prob_options) {
// https://github.com/d3/d3-format
// "for human consumption"
return prob_options.data.is_happen;
});
//there are two slices; take only the one which is happening;
// that is the best way to represent a binary probability pie
var is_happening_slice = is_happening_slices[0];
return is_happening_slice.data.prob;
}
var pie_text_func = function (d) {
return pie_text_format(pie_text_val(d));
};
var pie_group_labels = pie_groups
.append("g")
.attr("class", 'pie-label')
.append('text')
.text(pie_text_func);
var raised_label_height_offset = radius * 1.75;
var together_pie_group_label = svg
.append("g")
.attr('transform', together_pie_translate_func)
.attr("class", 'together-pie-label')
.append('text')
.attr('y', -radius * 1.2)
.text('=100%');
var together_pie_group_label_add = svg
.append("g")
.attr('transform', together_pie_translate_func)
.attr("class", 'together-pie-label-add')
.append('text')
// .attr('fill', 'white')
// .attr('y', -radius * 1.7)
//this is same as the labels
// .attr('y', -radius * 1.2)
.attr('y', -raised_label_height_offset)
.text('+');
together_pie_group_label_add.on('click', toggle_together_func);
sum_line_label_button.on('click', toggle_together_func);
sum_line_pie_button.on('click', toggle_together_func);
var together_pie_group_label_clip_width = 200;
var together_pie_group_label_clip_rect = together_pie_group_label_clip
.append('rect')
//No need to transform it
// .attr('transform', overlapping_pie_translate_func)
.attr('x', -together_pie_group_label_clip_width / 2)
.attr('width', together_pie_group_label_clip_width)
.attr('height', 40);
together_pie_group_label
.style('clip-path', 'url(#' + together_pie_group_label_clip_id + ')');
var normal_label_height_offset = radius * 1.2;
var original_pie_group_labels = function () {
together_pie_group_label_clip_rect
.transition()
// No delay on removal
// .delay(750)
.ease(d3.easeCircleOut)
.duration(750)
.attr('y', -normal_label_height_offset + 10)
pie_group_labels
.transition()
.ease(d3.easeCircleOut)
.duration(750)
.attr('y', -normal_label_height_offset)
.attr('x', 0);
}
original_pie_group_labels();
var together_pie_group_labels = function () {
together_pie_group_label_clip_rect
.transition()
// .delay(500)
.ease(d3.easeCircleOut)
.duration(750)
.attr('y', -radius * 1.2 - 40)
pie_group_labels
.transition()
.ease(d3.easeCircleOut)
.duration(750)
.attr('y', - raised_label_height_offset)
.attr('x', function (d, i) { return (i ? 1 : -1) * 60; });
}
// g2 = svg.append("g").attr("transform", "translate(" + 3 * width / 2 + "," + height / 2 + ")");
/* the data cannot be bound before attrTween,
data binding updates the current value with a new value
and once data binding does that; attrTween can only see the new value */
var arc_groups = pie_groups.selectAll(".arc")
.data(function (d) { return d; });
var arc_groups = arc_groups
.enter()
.append("g")
.attr("class", function (d, i) {
return 'arc ' + (d.data.is_happen ? 'happen' : 'not-happen');
});
arc_groups
.append('path')
.attr('d', arc_path);
var draw_pie = function (data) {
//TODO: Use webAnimationRequestFrame or whatever it's called
var scroll_pie_data = get_scroll_pie_data();
//Necessary to bind at least the outer layer of data
//for the sake of the text function
svg.selectAll('g.prob-pie')
.data(scroll_pie_data);
//https://bl.ocks.org/mbostock/3808218
//https://stackoverflow.com/questions/47066905/d3-merge-function
svg
.selectAll('g.prob-pie')
.each(function (prob_pie, pie_i) {
var current_pie_data = scroll_pie_data[pie_i];
d3.select(this)
.selectAll('.arc')
.select('path')
.transition()
// https://github.com/d3/d3-ease
.ease(d3.easeCircleOut)
.duration(750)
// https://github.com/d3/d3-transition#transition_attrTween
// http://javascript.tutorialhorizon.com/2015/03/05/creating-an-animated-ring-or-pie-chart-in-d3js/
.attrTween('d', tween_each_arc(current_pie_data))
d3.select(this)
.select('.pie-label text')
.text(pie_text_func);
// .text(are_together ? pie_text_format(1) : pie_text_func);
});
}
draw_pie();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment