Public
Edited
Aug 14, 2023
Paused
1 fork
Insert cell
Insert cell
Insert cell
md`date to stop playing. Ideally this should be a only a couple days in the past since data is usually updated each day`
Insert cell
d3.timeDay.offset(d3.utcDay(), -2)
Insert cell
endPlayDate = d3.timeDay.offset(d3.utcDay(), -2) //new Date("2022-06-01")
Insert cell
Insert cell
brushedData
Insert cell
Insert cell
viewof time1 = Scrubber(datesToPlot, {
width: 0,
delay: 100,
initial: newNum,
autoplay: false,
loop: false,
format: (d) => ""
})
Insert cell
Insert cell
Insert cell
mutable newNum = datesToPlot[datesToPlot.length - 1]
Insert cell
brushedData
Insert cell
// brushedDataMHW.push({
// date: new Date("2022-08-20"),
// none: 0,
// Moderate: 0,
// Strong: 0
// })
Insert cell
brusedAllDates[brusedAllDates.length - 1]
Insert cell
// {
// if (
// dateExtent[1].toISOString().substring(0, 7) + "-01" ===
// brusedAllDates[brusedAllDates.length - 1]
// ) {
// const temp = brushedDataMHW.filter(d => d.date != brusedAllDates[brusedAllDates.length - 1])
// }
// }
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
Insert cell
Insert cell
monthlyGrouped[115]
Insert cell
mutable debug1 = null
Insert cell
viewof focus = {
if (colorView === "Heatwaves") {
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, focusHeight])
.style("display", "block");

const x = d3
.scaleTime()
.domain(dateExtent)
.range([margin.left, width - margin.right]);

const brush = d3
.brushX()
.extent([
[margin.left, 0.5],
[width - margin.right, focusHeight - margin.bottom + 0.5]
])
.on("brush", brushed)
.on("end", brushended);

const defaultSelection = [
x(d3.utcYear.offset(x.domain()[1], -1)),
x.range()[1]
];

svg.append("g").call(xAxis, x, focusHeight).attr("class", "axisWhite");
let previousS0, previousS1;

const chartData = stack(monthlyGrouped);

const groups = svg
.append("g")
// Each layer of the stack goes in a group
// the group contains that layer for all countries
.selectAll("g")
.data(chartData)
.join("g")
// rects in the same layer will all have the same color, so we can put it on the group
// we can use the key on the layer's array to set the color
.style("fill", (d, i) => {
return colors.get(d.key);
});
// .attr("d", area(x, y.copy().range([focusHeight - margin.bottom, 4])));

groups
.selectAll("rect")
// Now we place the rects, which are the children of the layer array
.data((d) => d)
.join("rect")
.attr("x", (d) => {
// console.log(d.data.date);
return x1(new Date(d.data.date).toISOString().substring(0, 10));
})
.attr("y", (d) => y(d[1]))
.attr("height", (d) => y(d[0]) - y(d[1]))
.attr("width", x1.bandwidth());

const gb = svg.append("g").call(brush);
gb.call(brush.move, defaultSelection);

function brushed({ selection }) {
if (selection) {
// console.log("fire1");
var s = selection || x.range();

svg.property("value", selection.map(x.invert, x).map(d3.utcMonth.ceil));
svg.dispatch("input");

if (((s[1] - s[0]) / width) * 120 > 30) {
gb.call(brush.move, [previousS0, previousS1]);
return;
}
previousS0 = s[0];
previousS1 = s[1];
}
}

function brushended({ selection }) {
if (!selection) {
gb.call(brush.move, [defaultSelection]);
}
}
return svg.node();

/////
} else {
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, focusHeight])
.style("display", "block");

const x = d3
.scaleTime()
.domain(dateExtent)
.range([margin.left, width - margin.right]);

const brush = d3
.brushX()
.extent([
[margin.left, 0.5],
[width - margin.right, focusHeight - margin.bottom + 0.5]
])
.on("brush", brushed)
.on("end", brushended);

const defaultSelection = [
x(d3.utcYear.offset(x.domain()[1], -1)),
x.range()[1]
];

svg.append("g").call(xAxis, x, focusHeight).attr("class", "axisWhite");
let previousS0, previousS1;
// svg.append("path")
const bars = svg
.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", (d) => x1(d.date.toISOString().substring(0, 10)))
.attr("y", (d) => {
return y(1);
})
.attr("width", (d) => x1.bandwidth())
.attr("height", (d) => y(0) - y(1))
// .attr("fill", (d) => sstaColors(d.value));
.attr("fill", (d) => (d.value === -99 ? "#ddd" : sstaColors(d.value)));
// .attr("d", area(x, y.copy().range([focusHeight - margin.bottom, 4])));

const gb = svg.append("g").call(brush);
gb.call(brush.move, defaultSelection);

function brushed({ selection }) {
// mutable debug1 = selection;
if (selection) {
// console.log("fire1");
var s = selection || x.range();

svg.property("value", selection.map(x.invert, x).map(d3.utcMonth.ceil));
svg.dispatch("input");

if (
((s[1] - s[0]) / width) * 120 > 30 ||
((s[1] - s[0]) / width) * 120 < 2
) {
gb.call(brush.move, [previousS0, previousS1]);
return;
}
previousS0 = s[0];
previousS1 = s[1];
}
}

function brushended({ selection }) {
if (!selection) {
mutable debug1 = defaultSelection;
gb.call(brush.move, [previousS0, previousS1]); // changed from defaultSelection so that a single click doesn't mess things up
}
}

return svg.node();
}
}
Insert cell
Insert cell
Insert cell
Inputs.table(alldays)
Insert cell
clickedSite
Insert cell
new Date(clickedSite[0].date) < new Date(limitsDelayed[1])
Insert cell
// fill gaps in bouy data with nan so chart doesn't break

alldays = {
const alldays = d3.timeDay
.range(new Date(focus[0]), focus[1])
.map((d) => d.toISOString().substring(0, 10));
const out = [];
alldays.forEach((day, i) => {
let isData = clickedSite.find((d) => +d.date === +new Date(day));

isData === undefined
? out.push({
station: siteClicked,
sst: NaN,
ssta: NaN,
date: day
})
: out.push(isData);
});

return out;
}
Insert cell
alldays
Insert cell
console.log(new Date(alldays[0]))
Insert cell
console.log(clickedSite[0].date)
Insert cell
+clickedSite[0].date === +new Date(alldays[0])
Insert cell
alldays.length
Insert cell
alldays
Insert cell
clickedSite.find((d) => +d.date === +new Date(alldays[0]))
Insert cell
tempToShow === undefined

Insert cell
Insert cell
mutable siteClicked = 16
Insert cell
Insert cell
Insert cell
Insert cell
limitsDelayed = {
await Promises.delay(1000, ""); // delay returning
return focus;
}
Insert cell
Insert cell
// buttonStyle = faStyle({ solid: true })
Insert cell
// import { Player, faStyle } from "2b1bbd5c6560d3d0"
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
monthlyGrouped
Insert cell
brusedAllDates = d3.timeMonth
.range(new Date(focus[0]), focus[1])
.map((d) => d.toISOString().substring(0, 10))
Insert cell
Insert cell
x = d3
.scaleTime()
.domain(focus)
.range([margin.left, width - margin.right])
Insert cell
xMHW = d3
.scaleTime()
.domain(focus)
.range([margin.left, width - margin.right]);
Insert cell
stack = d3.stack().keys(cats)
Insert cell
brushedData = data.filter(
(d) => d.date >= focus[0] && new Date(d.date) < new Date(focus[1])
)
Insert cell
sstaColors = d3.scaleDiverging(d3.interpolateRdBu).domain([4, 0, -4])
Insert cell
Insert cell
Insert cell
new Date(data[data.length - 1].date).toISOString().substring(0, 7) <
new Date().toISOString().substring(0, 7)
Insert cell
new Date(data[data.length - 1].date.toISOString().substring(0, 7) + "-01")
Insert cell
new Date(new Date().toISOString().substring(0, 7) + "-01")
Insert cell
data[data.length - 1].date
Insert cell
dataToPlot = {
if (
new Date(data[data.length - 1].date).toISOString().substring(0, 7) <
new Date().toISOString().substring(0, 7)
) {
data.push({
date: new Date(new Date().toISOString().substring(0, 7) + "-01"),
value: -99
});
}
return data;
}
Insert cell
data = {
const out = [];
Object.keys(dataSsta).forEach((d) => {
out.push({
date: new Date(d.slice(0, 4) + "-" + d.slice(-2)),
value: dataSsta[d][0]
});
});

return out;
}
Insert cell
ns = Inputs.text().classList[0] // to customize radio styling
Insert cell
datesToPlot = datesCopy.filter(
(d) => d >= limitsDelayed[0] && d <= limitsDelayed[1]
)
Insert cell
Insert cell
Insert cell
Insert cell
buoys.find((d) => d.long_name === siteClickeds).pk
Insert cell
siteClickeds
Insert cell
viewof siteClickeds = Inputs.select(
[null].concat(buoys.map((d) => d.long_name)),
{
label: "site",
value: "North Hecate Strait"
}
)
Insert cell
clickedSite
Insert cell
new Date(time1).toISOString().substring(0, 10)
Insert cell
tempToShow = clickedSite.find(
(d) =>
new Date(d.date).toISOString().substring(0, 10) ===
new Date(time1).toISOString().substring(0, 10)
)
Insert cell
currentValue = {
let value;
if (clickedSite.length !== 0 && tempToShow !== undefined) {
value = tempToShow.ssta.toFixed(2);
} else {
value = "";
}

// if (clickedSite.length === 0) value = "";
return value;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
buoyDailyData[buoyDailyData.length - 1]
Insert cell
clickedSite = buoyDailyData.filter((d) => d.station === siteClicked)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// projection = d3
// .geoAlbers()
// .rotate([126, 0])
// .fitSize(
// [width, height],
// topojson.feature(BC_Midres, BC_Midres.objects.BC_Midres_latlng)
// )
Insert cell
height = 500
Insert cell
Insert cell
Insert cell
numFormat = d3.format(",d")
Insert cell
timeFormat = d3.timeFormat("%Y-%m-%d")
Insert cell
// import { Scrubber } from "@mbrownshoes/stylized-scrubber"
Insert cell
// import {legend} from "@d3/color-legend"
Insert cell
// import { BC_Midres } from "@mbrownshoes/how-i-start-maps-in-d3"
Insert cell
d3 = require("d3@6")
Insert cell
// import { textcolor } from "@observablehq/text-color-annotations-in-markdown";
Insert cell
mutable p = new Date(time1).toISOString().substring(0, 10)
Insert cell
Insert cell
alldates = d3.timeMonth
.range(new Date(dateExtent[0]), new Date(dateExtent[1]))
.map((d) => d.toISOString().substring(0, 10))
Insert cell
allmonths = [...new Set(mhwBarData.map((d) => d.date.slice(0, 7)))]
Insert cell
monthlyTots.filter((d) => d.date === "2013-01")
Insert cell
monthlyTots = {
const out = [];
allmonths.forEach((month) => {
let t = 0;
for (let i = 0; i < cats.length; i++) {
let s = d3.sum(
mhwBarData.filter((d) => {
return +new Date(d.month) === +new Date(month);
}),
(d) => d[cats[i]]
);
// 15541891 is the total amount of points
out.push({ date: month, [cats[i]]: s });
t += s;
// console.log(month, [cats[i]], s);
// console.log(t);
}
// console.log(t);
});
return out;
}
Insert cell
monthlyGrouped = {
const out = [];
groups.forEach((d) => {
let sum = 0;
d[1].forEach((d) => {
sum += Object.values(d)[1];
});
// return sum;
out.push({
date: new Date(d[0]),
[cats[0]]: d[1][0][cats[0]] / sum,
[cats[1]]: d[1][1][cats[1]] / sum,
[cats[2]]: d[1][2][cats[2]] / sum,
[cats[3]]: d[1][3][cats[3]] / sum,
[cats[4]]: d[1][4][cats[4]] / sum,
noData: 0,
sum: sum
});
});

// remove current month's incomplete data with -999
const corrected = out.map((d) => {
if (
new Date(d.date).toISOString().substring(0, 7) ===
new Date().toISOString().substring(0, 7)
) {
(d.none = 0),
(d.Moderate = 0),
(d.Strong = 0),
(d.Extreme = 0),
(d.Severe = 0),
(d.noData = 1);
}
return d;
});

return corrected;
}
Insert cell
monthlyGrouped[115]
Insert cell
monthlyGrouped[115].date
Insert cell
new Date().toISOString().substring(0, 7)
Insert cell
cats = ["none", "Moderate", "Strong", "Extreme", "Severe", "noData"]
Insert cell
Insert cell
mhwBarData = {
// const raw = await FileAttachment("monthlyMHW@4.json").json();
const raw = tt;
const out = [];
Object.keys(raw).forEach((d) => {
for (let i = 0; i < 1; i++) {
let tot = raw[d].reduce((a, b) => a + b, 0);
out.push({
date: d.replace(/(\d{4})(\d{2})(\d{2})/g, "$1-$2-$3"),
month: d.replace(/(\d{4})(\d{2})(\d{2})/g, "$1-$2-$3").slice(0, 7),
none: raw[d][0],
Moderate: raw[d][1],
Strong: raw[d][2],
Extreme: raw[d][3],
Severe: raw[d][4]
});
}
});
return out;
}
Insert cell
tt = fetch(
"https://raw.githubusercontent.com/HakaiInstitute/ssta_images/gh-pages/src/monthlyMHW.json",
{ Method: "GET" }
).then((response) => {
return response.json();
})
Insert cell
dataSsta["202203"]
Insert cell
dataSsta["202207"]
Insert cell
dataSsta = fetch(
"https://raw.githubusercontent.com/HakaiInstitute/ssta_images/gh-pages/src/monthly.json",
{ Method: "GET" }
).then((response) => {
return response.json();
})
Insert cell
dataSstaOld = FileAttachment("monthly@7.json").json()
Insert cell
import { Scrubber } from "@mbrownshoes/stylized-scrubber"
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