Published
Edited
Dec 3, 2021
Insert cell
Insert cell
Insert cell
task_1_solution = {
// Determine ratio for width and height
const width = 2;
const height = 1;
// Create svg to draw on
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
const iDataLen = data.length;
debugger;
svg.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('x', (d, i) => i*(width/iDataLen) )
.attr('y', d => (height*(1-(d.percentage_green_area/100))))
.attr('width', width*0.9/iDataLen)
.attr('height', d => (height*(d.percentage_green_area/100)))
.attr('percentageArea', d => d.percentage_green_area)
.attr('fill', '#a7d4b6');
// Return svg node
return svg.node();
}
Insert cell
Insert cell
task_2_solution = {
// Inside of these brackets you may write your solution code for task 2.
const width = 800;
const height = 400;
const iStartX = width*0.05;
const iStartY = height*0.9;
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
const iDataLen = data.length;
const iColWidth = width*0.9/iDataLen;
const iColMarginWidth = width*0.05/iDataLen;
let sPoints = sCoordToString(iStartX, iStartY)+', '+sCoordToString(iStartX*0.8, iStartY)+', ';
let iMax = 0; //max percentage in the data
let sPoints2 = '';
data.forEach(e => iMax=Math.max(iMax, e.percentage_green_area));
const iMaxRectHeight = height*(iMax/100);
const iVisPercentageLength = iMaxRectHeight/iMax;
let aAxesNumbers = [];
let index = 0;
let iNewY;
for (; index < iMax; index+=5) {
iNewY = iStartY-index*iVisPercentageLength;
sPoints2 += sCoordToStringFull(iStartX, iNewY);
aAxesNumbers.push({value: index, x: iStartX*0.8, y: iNewY})
}
iNewY = iStartY-iMax*iVisPercentageLength;
sPoints2 += sCoordToStringFull(iStartX, iNewY);
aAxesNumbers.push({value: '', x: iStartX*0.8, y: iNewY})
sPoints2 = sPoints2.slice(0, sPoints2.length-2);
let sPointsXAxis = sCoordToString(iStartX, iStartY*1.025)+', '+ sCoordToString(iStartX, iStartY)+', ';
let aXAxeValues =[];

let iNewX = iStartX;
iNewY = iStartY*1.025;
data.forEach((e, i) => {
iNewX = iNewX+iColWidth/2;
sPointsXAxis += sCoordToString(iNewX, iStartY)+', '+sCoordToString(iNewX, iNewY)+
', '+sCoordToString(iNewX, iStartY)+', ';
aXAxeValues.push({value: e.city, x:iNewX, y:iNewY});
iNewX+=iColWidth/2 +iColMarginWidth;
});
iNewX = width*0.999;
sPointsXAxis += sCoordToString(iNewX, iStartY)+', '+sCoordToString(iNewX, iNewY)

//debugger;
svg.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('x', (d, i) => width*0.05+i*(width*0.95/iDataLen) )
.attr('y', d => (height*(1-(d.percentage_green_area/100)))-height*0.1)
.attr('width', iColWidth)
.attr('height', d => (height*(d.percentage_green_area/100)))
.attr('percentageArea', d => d.percentage_green_area)
.attr('fill', '#a7d4b6')
svg.selectAll('text')
.data(aAxesNumbers)
.enter()
.append('text')
.attr('fill', 'black')
.attr("text-anchor", "end")
.attr("x", e => e.x)
.attr("y", e => e.y)
.attr('font-size', '12px')
.text(e=>e.value);

aXAxeValues.forEach(e => {
svg.append('text')
.attr('fill', 'black')
.attr("text-anchor", "middle")
.attr("x", e.x)
.attr("y", e.y*1.025)
.attr('font-size', '12px')
.text(e.value);
})
function sCoordToString(x, y) {
return x.toString()+','+y.toString()
}
function sCoordToStringFull(iStartX, iNewY) {
return sCoordToString(iStartX, iNewY)+', '+sCoordToString(iStartX*0.8, iNewY)+', '+sCoordToString(iStartX, iNewY)+', '
}
svg.append("polyline")
.style("stroke", "black")
.style("fill", "none")
.attr("points", sPoints2)
svg.append("polyline")
.style("stroke", "black")
.style("fill", "none")
.attr("points", sPointsXAxis);
return svg.node();
// If you open the web developer tools, you can inspect the data in the console output
console.log(data)
}
Insert cell
Insert cell
task_3_solution = {
// Inside of these brackets you may write your solution code for task 3.
const width = 800;
const height = 400;
const iStartX = width*0.05;
const iStartY = height*0.9;
// Create svg to draw on
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
const iDataLen = data.length;
const iColWidth = width*0.9/iDataLen;
const iColMarginWidth = width*0.05/iDataLen;
let sPoints = sCoordToString(iStartX, iStartY)+', '+sCoordToString(iStartX*0.8, iStartY)+', ';
let iMax = 0; //max percentage in the data
let sPoints2 = '';
data.forEach(e => iMax=Math.max(iMax, e.percentage_green_area));
const iMaxRectHeight = height*(iMax/100);
const iVisPercentageLength = iMaxRectHeight/iMax;
let aAxesNumbers = [];
let index = 0;
let iNewY;
for (; index < iMax; index+=5) {
iNewY = iStartY-index*iVisPercentageLength;
sPoints2 += sCoordToStringFull(iStartX, iNewY);
aAxesNumbers.push({value: index, x: iStartX*0.8, y: iNewY})
}
iNewY = iStartY-iMax*iVisPercentageLength;
sPoints2 += sCoordToStringFull(iStartX, iNewY);
aAxesNumbers.push({value: '', x: iStartX*0.8, y: iNewY})
sPoints2 = sPoints2.slice(0, sPoints2.length-2);
let sPointsXAxis = sCoordToString(iStartX, iStartY*1.025)+', '+ sCoordToString(iStartX, iStartY)+', ';
let aXAxeValues =[];

let iNewX = iStartX;
iNewY = iStartY*1.025;
data.forEach((e, i) => {
iNewX = iNewX+iColWidth/2;
sPointsXAxis += sCoordToString(iNewX, iStartY)+', '+sCoordToString(iNewX, iNewY)+', '+sCoordToString(iNewX, iStartY)+', ';
aXAxeValues.push({value: e.city, x:iNewX, y:iNewY});
iNewX+=iColWidth/2 +iColMarginWidth;
});
iNewX = width*0.999;
sPointsXAxis += sCoordToString(iNewX, iStartY)+', '+sCoordToString(iNewX, iNewY)

//debugger;
svg.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('x', (d, i) => width*0.05+i*(width*0.95/iDataLen) )
.attr('y', d => (height*(1-(d.percentage_green_area/100)))-height*0.1)
.attr('width', iColWidth)
.attr('height', d => (height*(d.percentage_green_area/100)))
.attr('percentageArea', d => d.percentage_green_area)
.attr('fill', '#a7d4b6')
.on('mouseover', function (d) {
d3.select(this)
.transition()
.attr('fill', '#88d19e');
svg.append('text')
.attr('fill', 'white')
.attr("text-anchor", "middle")
.attr("x", e => parseInt(this.getAttribute('x'))+parseInt(this.getAttribute('width')/2))
.attr("y", e => parseInt(this.getAttribute('y'))+parseInt(this.getAttribute('height')*0.1 ))
.attr("dy", "0")
.attr("class", "percentageHoverText")
.text(this.getAttribute('percentageArea'));
})
.on('mouseout', function(){
d3.selectAll(".percentageHoverText").remove()
d3.select(this)
.transition()
.attr('fill', '#a7d4b6');
});
svg.selectAll('text')
.data(aAxesNumbers)
.enter()
.append('text')
.attr('fill', 'black')
.attr("text-anchor", "end")
.attr("x", e => e.x)
.attr("y", e => e.y)
.attr('font-size', '12px')
.text(e=>e.value);

aXAxeValues.forEach(e => {
svg.append('text')
.attr('fill', 'black')
.attr("text-anchor", "middle")
.attr("x", e.x)
.attr("y", e.y*1.025)
.attr('font-size', '12px')
.text(e.value);
})
function sCoordToString(x, y) {
return x.toString()+','+y.toString()
}
function sCoordToStringFull(iStartX, iNewY) {
return sCoordToString(iStartX, iNewY)+', '+sCoordToString(iStartX*0.8, iNewY)+', '+sCoordToString(iStartX, iNewY)+', '
}
svg.append("polyline")
.style("stroke", "black")
.style("fill", "none")
.attr("points", sPoints2)
svg.append("polyline")
.style("stroke", "black")
.style("fill", "none")
.attr("points", sPointsXAxis);
return svg.node();
// If you open the web developer tools, you can inspect the data in the console output
console.log(data)
}
Insert cell
Insert cell
task_4_solution = {
// Inside of these brackets you may write your solution code for task 4.
// Determine the width and the height of the map display
const width = 800;
const height = 600;
// Create the projection function. This can be one of many: https://github.com/d3/d3-geo-projection
const projection = d3.geoMercator()
.translate([width/2, height/2]) // Move map to center of the display
.scale(100); // Adjust the scale: https://stackoverflow.com/questions/21565511/what-does-it-mean-to-scale-a-projection-in-d3
// Create svg element to draw on
const svg = d3.select(DOM.svg(width, height));
// Append the path elements for the different countries
svg.selectAll("path")
.data(mapData.features)
.enter().append("path")
.attr("fill", 'rgb(230, 230, 230)')
.attr("stroke", 'rgb(200, 200, 200)')
.attr("d", d3.geoPath(projection));
//originally longitude/lattitude are 360/180, but the map here is 4/3, thus we need to scale the points
const fLongitudePixelLen = (76/100)*(width/2)/180;
const fLatitudePixelLen = (59/100)*(height/2)/90;
const fCenterX=width/2;
const fCenterY=height/2;

svg.selectAll('circle')
.data(data)
.enter()
.append('circle')
.attr('cx', d => fCenterX+ (d.longitude*fLongitudePixelLen))
.attr('cy', d => fCenterY - (d.latitude*fLatitudePixelLen))
.attr('r', d=> d.percentage_green_area * (width/5000))
.attr('fill', '#a7d4b6');
return svg.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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