Published
Edited
Sep 18, 2020
Comments locked
Insert cell
Insert cell
d3 = require("d3@5")
Insert cell
cetacea = d3.csvParse(await FileAttachment("cetacea@1.csv").text())
Insert cell
firefly = d3.csvParse(await FileAttachment("firefly@3.csv").text())
Insert cell
Insert cell
{
//svg variables
let width = 720;
let height = 360;

//dataset cut
let dataLimit = 30000;

//create SVG artboard
let svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height);

let bg = svg
.append('rect')
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height);

//scales for converting geographic coordinates to pixels
let longitudeScale = d3
.scaleLinear()
.domain([-180, 60])
.range([0, width]);
let latitudeScale = d3
.scaleLinear()
.domain([-30, 90])
.range([height, 0]);

//scale for converting months to a number between 0 and 1
let monthScale = d3
.scaleLinear()
.domain([1, 12])
.range([0, 1]);

//loop through all items in dataset
for (let i = 0; i < dataLimit; i = i + 1) {
let xPosition = longitudeScale(parseFloat(cetacea[i].decimalLongitude));
let yPosition = latitudeScale(parseFloat(cetacea[i].decimalLatitude));

//draw circle for each item
svg
.append("circle")
.attr("cx", xPosition)
.attr("cy", yPosition)
.attr('r', 1.2)
.attr(
'fill',
d3.interpolateViridis(monthScale(parseInt(cetacea[i].month)))
)
.attr('stroke-width', '.5');
}

//show visualization in Observable
return svg.node();
}
Insert cell
Insert cell
{
//collector counting off the months
let months = {};

//look over
for (let i = 0; i < cetacea.length; i++) {
let sightingMonth;

//check if we need to add a zero in front of the month for Jan-Sept.
//so 5>05 but 11->11
if (parseInt(cetacea[i].month) < 10) {
sightingMonth = cetacea[i].year + "0" + cetacea[i].month;
} else {
sightingMonth = cetacea[i].year + cetacea[i].month;
}

//check if we have seen this month+year combo before
if (sightingMonth in months) {
//if we have seen it already, add one
months[sightingMonth]++;
} else {
//otherwise, make a new key
months[sightingMonth] = 1;
}
}

//create an arrays to organize data
let cetaceansByMonth = [];
for (let property in months) {
cetaceansByMonth.push({ name: property, count: months[property] });
}
console.log(cetaceansByMonth);

//sort months by their name - weird and not covered in the tutorial, but should make some intuitive sense?
//looks like an accessor function, right?
cetaceansByMonth.sort((a, b) => {
return parseInt(a.name) - parseInt(b.name);
});

//svg variablesj
let width = 800;
let height = 400;
let margin = 25;

//create SVG artboard
let svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height)
.attr("fill", "#ddd");

//create SVG background
let bg = svg
.append("rect")
.attr('x', 0)
.attr('y', 0)
.attr("width", width)
.attr("height", height);

//accessor function to find min and max counts
let monthMinMax = d3.extent(cetaceansByMonth, d => d.count);

//scales for counts to pixels and parameters
let monthSizeScale = d3
.scaleLinear()
.domain(monthMinMax)
.range([margin, height - margin * 2]);
let monthParameterScale = d3
.scaleLinear()
.domain(monthMinMax)
.range([0, 1]);

//how wide should each bar be?
let barWidth = (width - margin * 2) / cetaceansByMonth.length;

//loop through all items in dataset
for (let i = 0; i < cetaceansByMonth.length; i++) {
// for converting data to pixels
let barLength = monthSizeScale(parseFloat(cetaceansByMonth[i].count));
// for converting data to parameter between 0 and 1
let barParameter = monthParameterScale(
parseFloat(cetaceansByMonth[i].count)
);

//draw rectangle for each month
svg
.append("rect")
.attr("x", i * barWidth + margin)
//pesky needing to flip vertically
.attr("y", height - barLength - margin)
.attr('width', barWidth)
.attr('height', barLength)
.attr('fill', d3.interpolateViridis(barParameter));

//check if we are seeing a January...
if (cetaceansByMonth[i]["name"].slice(4) == "01") {
//add a textlabel for the new year
svg
.append("text")
.attr("x", i * barWidth + margin)
.attr("y", height - margin / 2)
.text(cetaceansByMonth[i]["name"].slice(0, 4))
.attr('fill', 'black')
.attr('font-family', 'courier')
.attr('font-size', 8);
}
}

//show visualization in Observable
return svg.node();
}
Insert cell
Insert cell
{
// Count countryCode
let countires = {};

// look over
for (let i = 0; i < cetacea.length; i++) {
let country = cetacea[i].countryCode;

if (country in countires) {
countires[country]++;
} else {
countires[country] = 1;
}
}
return countires; // how to descend the data?
}
Insert cell
Insert cell
{
// list up top 5 countries
let top5Countries = ["NL", "GB", "US", "NO", "DK"];

//collector counting off the months
let months = {};

let cetaceansByMonth = [];

// go through the loop for each top5
for (let c = 0; c < top5Countries.length; c++) {
for (let i = 0; i < cetacea.length; i++) {
// check countryCode of each datum corresponds to top5
if (cetacea[i].countryCode == top5Countries[c]) {
//look over and attatch countryCode to month to avoid overlapping
let sightingMonth = cetacea[i].countryCode + cetacea[i].month;

//check if we have seen this month+year combo before
if (sightingMonth in months) {
//if we have seen it already, add one
months[sightingMonth]++;
} else {
//otherwise, make a new key
months[sightingMonth] = 1;
}
}
}
}
//create an arrays to organize data
for (let property in months) {
cetaceansByMonth.push({
name: property,
count: months[property]
});
}

//svg variablesj
let width = 800;
let height = 400;
let margin = 25;

//create SVG artboard
let svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height)
.attr("fill", "#e5d8bd");

//create SVG background
let bg = svg
.append("rect")
.attr('x', 0)
.attr('y', 0)
.attr("width", width)
.attr("height", height);

//accessor function to find min and max counts
let monthMinMax = d3.extent(cetaceansByMonth, d => d.count);

//scales for counts to parameters
let monthParameterScale = d3
.scaleLinear()
.domain(monthMinMax)
.range([0, 1]);

// calculate the gap between each vertical line
let verticalGap = (height - margin * 2) / 12;

// scales for counts to pixels
let monthSizeScale = d3
.scaleLinear()
.domain(monthMinMax)
.range([0, verticalGap]);

// calculate the gap between each horizontal line
let horizontalGap = (width - margin * 2) / top5Countries.length;

// loop throught all items in dataset
for (let i = 0; i < cetaceansByMonth.length; i++) {
for (let c = 0; c < top5Countries.length; c++) {
if (cetaceansByMonth[i]["name"].slice(0, 2) == top5Countries[c]) {
// for converting data to pixels
let circleRadius = monthSizeScale(
parseFloat(cetaceansByMonth[i].count)
);

// for converting data to parameter between 0 and 1
let barParameter = monthParameterScale(
parseFloat(cetaceansByMonth[i].count)
);

let monthNumber = cetaceansByMonth[i]["name"].slice(2);

// draw circle for each month
svg
.append("circle")
.attr("cx", (c + 1) * horizontalGap)
.attr("cy", monthNumber * verticalGap)
.attr("r", circleRadius)
.attr("fill", d3.interpolateViridis(barParameter))
.attr("opacity", .5);

// label country name
svg
.append("text")
.attr("x", (c + 1) * horizontalGap)
.attr("y", height - margin / 2)
.text(cetaceansByMonth[i]["name"].slice(0, 2))
.attr("fill", "black")
.attr("text-anchor", "middle")
.attr("fill", "#616161")
.attr("font-family", "Arial, Helvetica, sans-serif");

let monthName = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec'
];

// label month name
svg
.append("text")
.attr("x", margin)
.attr("y", monthNumber * verticalGap)
.text(monthName[monthNumber - 1])
.attr("fill", "black")
.attr("transform", "translate(0 5)")
.attr("fill", "#616161")
.attr("font-size", "0.75em")
.attr("font-family", "Arial, Helvetica, sans-serif");
}
}
}

//show visualization in Observable
return svg.node();
}
Insert cell
Insert cell
{
//svg variables
let width = 720;
let height = 360;

//dataset cut
let dataLimit = 20000;

//create SVG artboard
let svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height);

let bg = svg
.append('rect')
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height);

//scales for converting geographic coordinates to pixels
let longitudeScale = d3
.scaleLinear()
.domain([-140, -50])
.range([0, width]);
let latitudeScale = d3
.scaleLinear()
.domain([10, 55])
.range([height, 0]);

//scale for converting months to a number between 0 and 1
let monthScale = d3
.scaleLinear()
.domain([1, 12])
.range([0, 1]);

//loop through all items in dataset
for (let i = 0; i < dataLimit; i = i + 1) {
let xPosition = longitudeScale(parseFloat(firefly[i].decimalLongitude));
let yPosition = latitudeScale(parseFloat(firefly[i].decimalLatitude));

//draw circle for each item
svg
.append("circle")
.attr("cx", xPosition)
.attr("cy", yPosition)
.attr('r', 1.2)
.attr('fill', d3.interpolateTurbo(monthScale(parseInt(firefly[i].month))))
.attr('stroke-width', '.5');
}

//show visualization in Observable
return svg.node();
}
Insert cell
Insert cell
{
//collector counting off the months
let months = {};

//look over
for (let i = 0; i < firefly.length; i++) {
// select data after 2010 and eliminate non month data
if (firefly[i].year >= 2010 && firefly[i].month != "") {
let sightingMonth;
//check if we need to add a zero in front of the month for Jan-Sept.
//so 5>05 but 11->11
if (parseInt(firefly[i].month) < 10) {
sightingMonth = firefly[i].year + "0" + firefly[i].month;
} else {
sightingMonth = firefly[i].year + firefly[i].month;
}

//check if we have seen this month+year combo before
if (sightingMonth in months) {
//if we have seen it already, add one
months[sightingMonth]++;
} else {
//otherwise, make a new key
months[sightingMonth] = 1;
}
}
}

//create an arrays to organize data
let firefliesByMonth = [];
for (let property in months) {
firefliesByMonth.push({ name: property, count: months[property] });
}

//sort months by their name - weird and not covered in the tutorial, but should make some intuitive sense?
//looks like an accessor function, right?
firefliesByMonth.sort((a, b) => {
return parseInt(a.name) - parseInt(b.name);
});

//svg variables
let width = 800;
let height = 400;
let margin = 25;

//create SVG artboard
let svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height)
.attr("fill", "#ddd");

//create SVG background
let bg = svg
.append("rect")
.attr('x', 0)
.attr('y', 0)
.attr("width", width)
.attr("height", height);

//accessor function to find min and max counts
let monthMinMax = d3.extent(firefliesByMonth, d => d.count);

//scales for counts to pixels and parameters
let monthSizeScale = d3
.scaleLinear()
.domain(monthMinMax)
.range([margin, height - margin * 2]);
let monthParameterScale = d3
.scaleLinear()
.domain(monthMinMax)
.range([0, 1]);

//how wide should each bar be?
let barWidth = (width - margin * 2) / firefliesByMonth.length;

//loop through all items in dataset
for (let i = 0; i < firefliesByMonth.length; i++) {
// for converting data to pixels
let barLength = monthSizeScale(parseFloat(firefliesByMonth[i].count));
// for converting data to parameter between 0 and 1
let barParameter = monthParameterScale(
parseFloat(firefliesByMonth[i].count)
);

//draw rectangle for each month
svg
.append("rect")
.attr("x", i * barWidth + margin)
//pesky needing to flip vertically
.attr("y", height - barLength - margin)
.attr('width', barWidth)
.attr('height', barLength)
.attr('fill', d3.interpolateTurbo(barParameter));

//check if we are seeing a January...
if (firefliesByMonth[i]["name"].slice(4) == "01") {
//add a textlabel for the new year
svg
.append("text")
.attr("x", i * barWidth + margin)
.attr("y", height - margin / 2)
.text(firefliesByMonth[i]["name"].slice(0, 4))
.attr('fill', 'black')
.attr('font-family', 'courier')
.attr('font-size', 8);
}
}

//show visualization in Observable
return svg.node();
}
Insert cell
Insert cell
Insert cell
{
// list up top 5 countries
let top5Countries = ["GB", "US", "FR", "SE", "CA"];

//collector counting off the months
let months = {};

let firefliesByMonth = [];

// go through the loop for each top5
for (let c = 0; c < top5Countries.length; c++) {
for (let i = 0; i < firefly.length; i++) {
// check countryCode of each datum corresponds to top5
if (
firefly[i].countryCode == top5Countries[c] &&
firefly[i].month != ""
) {
//look over and attatch countryCode to month to avoid overlapping
let sightingMonth = firefly[i].countryCode + firefly[i].month;

//check if we have seen this month+year combo before
if (sightingMonth in months) {
//if we have seen it already, add one
months[sightingMonth]++;
} else {
//otherwise, make a new key
months[sightingMonth] = 1;
}
}
}
}
//create an arrays to organize data
for (let property in months) {
firefliesByMonth.push({
name: property,
count: months[property]
});
}

//svg variablesj
let width = 800;
let height = 400;
let margin = 25;

//create SVG artboard
let svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height)
.attr("fill", "#e5d8bd");

//create SVG background
let bg = svg
.append("rect")
.attr('x', 0)
.attr('y', 0)
.attr("width", width)
.attr("height", height);

//accessor function to find min and max counts
let monthMinMax = d3.extent(firefliesByMonth, d => d.count);

//scales for counts to parameters
let monthParameterScale = d3
.scaleLinear()
.domain(monthMinMax)
.range([0, 1]);

// calculate the gap between each vertical line
let verticalGap = (height - margin * 2) / 12;

// scales for counts to pixels
let monthSizeScale = d3
.scaleLinear()
.domain(monthMinMax)
.range([0, verticalGap]);

// calculate the gap between each horizontal line
let horizontalGap = (width - margin * 2) / top5Countries.length;

// loop throught all items in dataset
for (let i = 0; i < firefliesByMonth.length; i++) {
for (let c = 0; c < top5Countries.length; c++) {
if (firefliesByMonth[i]["name"].slice(0, 2) == top5Countries[c]) {
// for converting data to pixels
let circleRadius = monthSizeScale(
parseFloat(firefliesByMonth[i].count)
);

// for converting data to parameter between 0 and 1
let barParameter = monthParameterScale(
parseFloat(firefliesByMonth[i].count)
);

let monthNumber = firefliesByMonth[i]["name"].slice(2);

// draw circle for each month
svg
.append("circle")
.attr("cx", (c + 1) * horizontalGap)
.attr("cy", monthNumber * verticalGap)
.attr("r", circleRadius)
.attr("fill", d3.interpolateTurbo(barParameter))
.attr("opacity", .5);

// label country name
svg
.append("text")
.attr("x", (c + 1) * horizontalGap)
.attr("y", height - margin / 2)
.text(firefliesByMonth[i]["name"].slice(0, 2))
.attr("text-anchor", "middle")
.attr("fill", "#616161")
.attr("font-family", "Arial, Helvetica, sans-serif");

let monthName = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec'
];

// label month name
svg
.append("text")
.attr("x", margin)
.attr("y", monthNumber * verticalGap)
.text(monthName[monthNumber - 1])
.attr("fill", "black")
.attr("transform", "translate(0 5)")
.attr("fill", "#616161")
.attr("font-size", "0.75em")
.attr("font-family", "Arial, Helvetica, sans-serif");
}
}
}

//show visualization in Observable
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