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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more