Public
Edited
Oct 21, 2023
1 fork
Insert cell
Insert cell
Insert cell
Insert cell
data = FileAttachment("tested.csv").csv()
Insert cell
// Calculated the passengers in each class
classType = d3.rollup(
data,
group =>group.length,
passenger=>passenger.Pclass
)
Insert cell
// Give each field a name
aggregated = Array.from(classType, ([key, value]) => ({
classType: key,
Number: value
}));
Insert cell
passengers_class = aggregated.map(item => item.Number);
Insert cell
// find the max value of number of passengers in each class to define x = f()
max_passenger = d3.max(passengers_class)
Insert cell
survived = d3.filter(
data,
passenger => passenger.Survived =="1"
)
Insert cell
q1 = d3.rollup(
survived,
group => group.length,
passenger => passenger.Pclass,
)
Insert cell
// Find out how many people survived in each class
q1Data = Array.from(q1, ([key, value]) => ({
classType: key,
value: value
}));
Insert cell
// calculate the percentage of passengers survived in each class
results = {const results = aggregated.map(item => {
const matchingQ1Item = q1Data.find(qItem => qItem.classType === item.classType);
if (matchingQ1Item) {
const percentage = ((matchingQ1Item.value / item.Number) * 100).toFixed(0);
return {
classType: item.classType,
value: matchingQ1Item.value,
percentage: parseFloat(percentage)
};
} else {
return null; // or handle the case when there is no matching q1Data for an item in aggregated
}
});
return results
}
Insert cell
totalWidth = width/1.5
Insert cell
totalHeight = 400
Insert cell
margin = ({top: 20, bottom: 45, left: 75, right: 10})
Insert cell
visWidth = totalWidth - margin.left - margin.right
Insert cell
visHeight = totalHeight - margin.top - margin.bottom
Insert cell
y = d3.scaleBand()
.domain(["3","2","1"])
.range([0,visHeight])
.padding(0.5)


Insert cell
y(3)
Insert cell
y("3")
Insert cell
x = d3.scaleLinear()
.domain([0,max_passenger])
.range([0, visWidth])
.nice()
Insert cell
x(218)
Insert cell
totalColor = `rgb(255, 204, 153)`
Insert cell
Insert cell
{

const svg = d3.create('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);

const g = svg.append("g")
.attr('transform', `translate(${margin.left}, ${margin.top})`);

// create bars for total number of passengers
g.selectAll('.rect1')
.data(aggregated)
.join('rect')
.attr('x',0)
.attr('y', d => y(d.classType))
.attr('width', d => x(d.Number))
.attr('height', y.bandwidth())
.attr('fill', totalColor);


//define new tick for y-axis
const yText = {
"1": "First",
"2": "Second",
"3": "Third",
};
const yAxis = d3.axisLeft(y).tickFormat(d => yText[d]);
const xAxis = d3.axisBottom(x);
// add a group for the y-axis
g.append('g')
.call(yAxis)
.call(g => g.select('.domain').remove())
.append('text')
.attr('fill', 'black')
.attr('font-family', 'sans-serif')
.attr('x', 0)
.attr('y', 0)
.text("Class Type")
.attr('font-size', '14px');
// add a group for the x-axis
g.append('g')
.attr('transform', `translate(0, ${visHeight})`)
.call(xAxis)
.call(g => g.select('.domain').remove())
.append('text')
.attr('fill', 'black')
.attr('font-family', 'sans-serif')
.attr('x', visWidth / 2)
.attr('y', 40)
.text("Number of passengers")
.attr('font-size', '14px');

// add bars to represent survived passengers in each class
g.selectAll('.rect2')
.data(q1Data)
.join('rect')
.attr('x',0)
.attr('y', d => y(d.classType))
.attr('width', d => x(d.value))
.attr('height', y.bandwidth())
.attr('fill', 'orange');

// add legend
svg.append('rect')
.attr('x', 400)
.attr('y',5)
.attr('width',20)
.attr('height',20)
.attr('fill', 'orange');
svg.append('text')
.attr('x', 425)
.attr('y',20)
.text('Survived')
.attr('font-size', '14px');
;
svg.append('rect')
.attr('x', 515)
.attr('y',5)
.attr('width',20)
.attr('height',20)
.attr('fill', totalColor);

svg.append('text')
.attr('x', 540)
.attr('y',20)
.text('Unsurvived')
.attr('font-size', '14px');

;

// add percentage information to each bar
g.selectAll('.text')
.data(results)
.join('text')
.attr('x',d => x(d.value))
.attr('y', d => y(d.classType))
.text(d=>d.percentage+" % ");
return svg.node();
}
Insert cell
Insert cell
// select data needed
result = data.filter(item => item.Fare !== '').filter(item => parseFloat(item.Fare) !== 0).map(item => (
{
Fare: item.Fare,
PClass: item.Pclass,
Embarked: item.Embarked
}
))
Insert cell
Pclass = new Set(data.map(i=>i.Pclass))
Insert cell
embark_place = data.map(item => item.Embarked)
Insert cell
unique_embark = ['S', 'C','Q']
Insert cell
Insert cell

distance = ({
"S": "3216",
"C": "3132",
"Q": "2825",
}
)
Insert cell
width
Insert cell
maxCount = result.map(i=>parseFloat(i.Fare))
Insert cell
maxcount0= d3.max(maxCount)
Insert cell
avg_matrix = {
const fareSumMap = {};
const fareCountMap = {};

result.forEach(item => {
const key = item.PClass + item.Embarked;
if (!fareSumMap[key]) {
fareSumMap[key] = 0;
fareCountMap[key] = 0;
}
fareSumMap[key] += parseFloat(item.Fare);
fareCountMap[key]++;
});

const result0 = Object.keys(fareSumMap).map(key => {
const [pclass, embarked] = key.split('');
const avgFare = (fareSumMap[key] / fareCountMap[key]).toFixed(2);
return { Fare: avgFare, PClass: pclass, Embarked: embarked };
});

return result0;
}
Insert cell
maximum_res = d3.rollups(
result,
group => d3.max(group, d=> d.Fare),
d =>d.PClass,
d =>d.Embarked
)
Insert cell
max_matrix = maximum_res.flatMap(([PClass, data]) =>
data.map(([Embarked, max_fare]) => ({ Fare: parseFloat(max_fare).toFixed(2), PClass, Embarked }))
);
Insert cell
minimum_res = d3.rollups(
result,
group => d3.min(group, d=> d.Fare),
d =>d.PClass,
d =>d.Embarked
)
Insert cell
min_matrix = minimum_res.flatMap(([PClass, data]) =>
data.map(([Embarked, max_fare]) => ({ Fare: parseFloat(max_fare).toFixed(2), PClass, Embarked }))
);
Insert cell
median_res = d3.rollups(
result,
group => d3.median(group, d=> d.Fare),
d =>d.PClass,
d =>d.Embarked
)
Insert cell
median_matrix = median_res.flatMap(([PClass, data]) =>
data.map(([Embarked, max_fare]) => ({ Fare: parseFloat(max_fare).toFixed(2), PClass, Embarked }))
);
Insert cell
point_radius = d3.scaleLinear()
.domain([0, d3.max(max_matrix, d=>d.Fare)])
.range([0,40])
Insert cell
columns = ['average','maximum','minimum','median']
Insert cell
viewof DataInfo = Inputs.radio(columns,{value:'average', label:'data info'}) ;
Insert cell
{
let matrix = avg_matrix;
// // set p
if(DataInfo == 'average'){
matrix = avg_matrix
}
if(DataInfo =='maximum'){
matrix = max_matrix
}
if(DataInfo =='minimum'){
matrix = min_matrix
}
if(DataInfo=='median'){
matrix = median_matrix
}
const margin = {top: 50, right: 120, bottom: 50, left: 120};
const visWidth = 500;
const visHeight = 500;

const svg = d3.create('svg')
.attr('width', visWidth + margin.left + margin.right)
.attr('height', visHeight + margin.top + margin.bottom);

const g = svg.append("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`);

// add title
g.append("text")
.attr("x", visWidth / 2)
.attr("y", -margin.top + 5)
.attr("text-anchor", "middle")
.attr("dominant-baseline", "hanging")
.attr("font-family", "sans-serif")
.attr("font-size", "16px")
.text("Titanic Fare Data by Travel Distance and Class Type");

// create scales
const x = d3.scalePoint()
.domain(Pclass)
.range([0,visHeight])
.padding(0.5)

const y = d3.scalePoint()
.domain(unique_embark)
.range([0,visWidth])
.padding(0.5)

// create and add axes

//define new tick for y-axis
const yText = {
"S": "Southampton",
"C": "Cherbourg",
"Q": "Queestown",
};

const xText = {
"1": "1st class",
"2": "2nd class",
"3": "3rd class",
};
const yAxis = d3.axisLeft(y).tickFormat(d => yText[d])
;
const xAxis = d3.axisBottom(x).tickFormat(d => xText[d])
;
// const xAxis = d3.axisBottom(x);

// const tooltip = d3.select('body')
// .append('div')
// .style('position', 'absolute')
// .style('z-index','10')
// .style('color','#3497db')
// .style('visibility','hidden')
// .style('font-size', '12px')
// .style('font-weight', 'bold')
// .text('test')
g.append("g")
.attr("transform", `translate(0, ${visHeight})`)
// add axis
.call(xAxis)
.call(g => g.select(".domain").remove())
// add grid lines
.call(g => g.selectAll('.tick line')
.clone()
.attr('stroke', '#d3d3d3')
.attr('y1', -visHeight)
.attr('y2', 0))
// add title
.append("text")
.attr("x", visWidth / 2)
.attr("y", 40)
.attr("fill", "black")
.attr("text-anchor", "middle")
.attr("font-size", "15px")
.text(" ");







g.append("g")
// add axis
.call(yAxis)
.call(g => g.select(".domain").remove())
// add grid lines
.call(g => g.selectAll('.tick line')
.clone()
.attr('stroke', '#d3d3d3')
.attr('x1', 0)
.attr('x2', visWidth))
// add title
.append("text")
.attr("x", -40)
.attr("y", visHeight / 2)
.attr("fill", "black")
.attr("dominant-baseline", "middle")
.attr("font-size", "15px")
.text(" ");

//draw circles to represent points
g.append("g")
.selectAll("circle")
.data(matrix)
.join("circle")
.attr("cx", d=>x(d.PClass))
.attr("cy", d=>y(d.Embarked))
.attr("fill", 'steelblue')
.attr("r", d=> point_radius(d.Fare))


.on('mouseenter', mouseEnter)
.on('mouseleave', mouseLeave);

// create tooltip
const tooltip = g.append('g')
.attr('visibility', 'hidden');
const tooltipHeight = 16;
// add a rectangle to the tooltip to serve as a background
const tooltipRect = tooltip.append('rect')
.attr('fill', 'black')
.attr('rx', 5)
.attr('height', tooltipHeight);
// add a text element to the tooltip to contain the label
const tooltipText = tooltip.append('text')
.attr('fill', 'white')
.attr('font-family', 'sans-serif')
.attr('font-size', 12)
.attr('y', 2) // offset it from the edge of the rectangle
.attr('x', 3) // offset it from the edge of the rectangle
.attr('dominant-baseline', 'hanging')
// handle hovering over a circle
function mouseEnter(event, d) {
// make the circle larger
d3.select(this)
.attr('r', point_radius(d.Fare) * 1.3);
// update the label's text and get its width
tooltipText.text(d.Fare);
const labelWidth = tooltipText.node().getComputedTextLength();
// set the width of the tooltip's background rectangle
// to match the width of the label, plus some extra space
tooltipRect.attr('width', labelWidth + 6);
// move the tooltip to the position of the circle (offset by a bit)
// and make the tooltip visible
const xPos = x(d.PClass) + point_radius(d.Fare) * 3;
const yPos = y(d.Embarked) - tooltipHeight / 2;

tooltip.attr('transform', `translate(${xPos},${yPos})`)
.attr('visibility', 'visible');
}
// handle leaving a circle
function mouseLeave(event, d) {
// reset the size of the circle
d3.select(this)
.attr('r', point_radius(d.Fare))
// make the tooltip invisible
tooltip
.attr('visibility', 'hidden');
}
return svg.node();

}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more