boxplot = {
const n = 20;
Math.seedrandom(seed);
let runif = (a, b, n) => {
let numbers = new Array();
for (let i = 0; i < n; i++){
numbers[i] = Math.round(Math.random() * (b-a) + a);
}
return numbers;
};
let data_penguins_height = runif(60, 70, n-4);
data_penguins_height = data_penguins_height.concat(runif(50, 55, 2));
data_penguins_height = data_penguins_height.concat(runif(75, 79, 2));
// add the randomly generated size to the cells
let penguins_container = document.querySelector("#penguin-container-boxplot").querySelectorAll(".penguin-hist");
for (let i = 0; i < n; i++){
const penguin = penguins_container[i];
let penguins_paragraphs = penguin.querySelectorAll("p");
if (penguins_paragraphs.length > 1) penguins_paragraphs[1].remove()
//penguins_paragraphs[0].querySelector("img").height = +data_penguins_height[i];
const p = document.createElement("p");
p.innerText = data_penguins_height[i].toString() + ' cm';
penguin.append(p);
}
// set the dimensions and margins of the graph
var margin = {top: 10, right: 30, bottom: 100, left: 200},
width = 600 - margin.left - margin.right,
height = 550 - margin.top - margin.bottom;
// append the svg object to the body of the page
d3.select("#penguins-boxplot").html("");
var svg = d3.select("#penguins-boxplot")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Compute summary statistics used for the box:
var data_sorted = data_penguins_height.sort(d3.ascending)
var q1 = d3.quantile(data_sorted, .25)
var median = d3.quantile(data_sorted, .5)
var q3 = d3.quantile(data_sorted, .75)
var interQuantileRange = q3 - q1
var min = q1 - 1.5 * interQuantileRange
var max = q3 + 1.5 * interQuantileRange
min = Math.min.apply(Math, data_sorted.filter(function(x){return x >= min}));
max = Math.max.apply(Math, data_sorted.filter(function(x){return x <= max}));
if (extra_info){
// Append the summary statistics to div element
let boxplot_summary = document.querySelector("#boxplot-summary");
boxplot_summary.innerHTML = '';
boxplot_summary.append(document.createElement("hr"));
let p = document.createElement("p");
p.innerHTML = "Q<sub>1</sub>: " + q1.toString() + " cm";
p.style.fontSize = "0.75em";
boxplot_summary.append(p);
p = document.createElement("p");
p.innerHTML = "Q<sub>2</sub>: " + median.toString() + " cm";
p.style.fontSize = "0.75em";
boxplot_summary.append(p);
p = document.createElement("p");
p.innerHTML = "Q<sub>3</sub>: " + q3.toString() + " cm";
p.style.fontSize = "0.75em";
boxplot_summary.append(p);
}
// Show the Y scale
var y = d3.scaleLinear()
//.domain([d3.min(data_penguins_height), d3.max(data_penguins_height)])
.domain([50, 80])
.range([height, 0]);
svg.call(d3.axisLeft(y).ticks(7));
// a few features for the box
var center = 100;
var width = 100;
// Show the main vertical line
svg
.append("line")
.attr("x1", center)
.attr("x2", center)
.attr("y1", y(min))
.attr("y2", y(q1))
.attr("stroke", "black");
svg
.append("line")
.attr("x1", center)
.attr("x2", center)
.attr("y1", y(q3))
.attr("y2", y(max))
.attr("stroke", "black");
// Show the box
svg
.append("rect")
.attr("x", center- width/2)
.attr("y", y(q3))
.attr("height", (y(q1)-y(q3)))
.attr("width", width)
.attr("stroke", "black");
//.style("fill", "#69b3a2");
// show median, min and max horizontal lines
svg
.selectAll("toto")
.data([min, max])
.enter()
.append("line")
.attr("x1", center-width/4)
.attr("x2", center+width/4)
.attr("y1", function(d){ return(y(d))})
.attr("y2", function(d){ return(y(d))})
.attr("stroke", "black");
if (extra_info){
svg.append("line")
.attr("x1", 0)
.attr("x2", center + width)
.attr("y1", y(q3 + 1.5*(q3-q1)))
.attr("y2", y(q3 + 1.5*(q3-q1)))
.attr("stroke", "black")
.attr("stroke-width", "1px")
.attr("stroke-opacity", "0.4")
.style("stroke-dasharray", ("3, 3"))
svg.append("line")
.attr("x1", 0)
.attr("x2", center + width)
.attr("y1", y(q1 - 1.5*(q3-q1)))
.attr("y2", y(q1 - 1.5*(q3-q1)))
.attr("stroke", "black")
.attr("stroke-width", "1px")
.attr("stroke-opacity", "0.4")
.style("stroke-dasharray", ("3, 3"))
}
svg.append("line")
.attr("x1", center-width/2)
.attr("x2", center+width/2)
.attr("y1", y(median))
.attr("y2", y(median))
.attr("stroke", "black")
.attr("stroke-width", "4px");
svg
.selectAll("circle")
.data(data_penguins_height.filter(x => x < min || x > max))
.enter()
.append("circle")
.attr("cx", center)
.attr("cy", d => y(d))
.attr("r", "3px")
.attr("stroke", "black")
.attr("fill", "black");
if (extra_info){
svg
.selectAll()
.data(data_penguins_height.filter(x => x >= min && x <= max))
.enter()
.append("circle")
.attr("cx", d => runif(center-width/6, center + width/6, 1))
.attr("cy", d => y(d))
.attr("r", "3px")
.attr("stroke", "blue")
.attr("fill", "blue");
// Appending a bunch of texts
svg.append("text")
.attr("text-anchor", "start")
.attr("x", center+width/2+5)
.attr("y", y(median-.35))
.html("Q")
.style('font-size', '20px')
.attr("fill", "black")
.append('tspan')
.text('2')
.style('font-size', '12px')
.attr('dx', '.1em')
.attr('dy', '.5em');
svg.append("text")
.attr("text-anchor", "start")
.attr("x", center+width/2+5)
.attr("y", y(q1-.35))
.html("Q")
.style('font-size', '20px')
.attr("fill", "black")
.append('tspan')
.text('1')
.style('font-size', '12px')
.attr('dx', '.1em')
.attr('dy', '.5em');
svg.append("text")
.attr("text-anchor", "start")
.attr("x", center+width/2+5)
.attr("y", y(q3-.35))
.html("Q")
.style('font-size', '20px')
.attr("fill", "black")
.append('tspan')
.text('3')
.style('font-size', '12px')
.attr('dx', '.1em')
.attr('dy', '.5em');
svg.append("text")
.attr("text-anchor", "start")
.attr("x", center+width/4+5)
.attr("y", y(max-.25))
.text("Largest point below the upper fence")
.style('font-size', '14px')
.attr("fill", "black");
svg.append("text")
.attr("text-anchor", "start")
.attr("x", center+width/4+5)
.attr("y", y(min-.25))
.text("Smallest point above the lower fence")
.style('font-size', '14px')
.attr("fill", "black");
svg.append("text")
.attr("text-anchor", "start")
.attr("x", center+width+5)
.attr("y", y(q3 + 1.5*(q3-q1)-.25))
.text("Upper fence: Q3 + 1.5 x IQR")
.style('font-size', '14px')
.attr("fill", "black");
svg.append("text")
.attr("text-anchor", "start")
.attr("x", center+width+5)
.attr("y", y(q1 - 1.5*(q3-q1)-.25))
.text("Lower fence: Q1 - 1.5 x IQR")
.style('font-size', '14px')
.attr("fill", "black");
}
// Y-label
svg.append("text")
.attr("text-anchor", "middle")
.attr("transform", "rotate(-90)")
.attr("x", -50)
.attr("y", y((85+45)/2))
.attr("class", 'axesLabel')
.text("Height (cm)")
.attr("fill", "black")
.style('transform-box', 'fill-box')
.style('transform-origin', '50% 50%');
svg.selectAll(".tick").selectAll("text").style('font-size', "14px");
svg.selectAll(".axesLabel").style('font-size', "24px");
}