Public
Edited
Jun 22, 2022
1 star
Insert cell
Insert cell
ind = dates.indexOf(time1)
Insert cell
<style>
/* match the scrubber's width to our race chart */
/* input[type="range"][name="i"] {
width: ${width-90}px !important;
} */
</style>
Insert cell
style = html`
<style>
.button {
color:lightgrey;
border: 0;
background: transparent;
box-sizing: border-box;
width: 100;
height: 74px;
border-color: transparent transparent transparent lightgrey;
transition: 100ms all ease;
cursor: pointer;
border-style: solid;
border-width: 37px 0 37px 60px;
}
.paused {
border-style: double;
border-width: 0px 0 0px 60px;
}
.button:hover {
border-color: transparent transparent transparent #404040;
}
input{
accent-color:white
}

</style>
`
Insert cell
test === null
Insert cell
test = null
Insert cell
today = d3.timeDay.offset(d3.utcDay(), -2) //d3.utcDay()
Insert cell
start = d3.timeDay.offset(today, -365)
Insert cell
textures = require("textures@1.2.0/dist/textures.js")
Insert cell
Insert cell
Insert cell
limitsDelayed = {
await Promises.delay(1500, ""); // delay returning
return limits;
}
Insert cell
limits
Insert cell
viewof limits = {
// document.querySelector('[name="b"]').disabled = true;
return brushFilterX(d3.extent(dates), {
defaultExtent: [start, d3.timeDay.offset(today, -1)]
});
}
Insert cell
Insert cell
(1 * 21) / 200
Insert cell
ns = Inputs.text().classList[0]
Insert cell
viewof colorView = Inputs.radio(["Anomaly", "Heatwaves"], {
value: "Anomaly",
format: (x) => html`<span style="color: white">${x}`
})
Insert cell
colorView
Insert cell
datesToPlot = datesCopy.filter(
(d) => d >= limitsDelayed[0] && d <= limitsDelayed[1]
)
Insert cell
// d3.timeDay.offset(limits[1], 1)
Insert cell
Insert cell
datesCopy = [...dates]
Insert cell
dateExtent = [new Date("2013-01-01"), new Date()] //d3.extent(HWStatus, (d) => new Date(d.date_start1))
Insert cell
Insert cell
Math.min(755, width - 1)
Insert cell
viewof time1 = Scrubber(datesToPlot, {
width: 0,
delay: 100,
autoplay: false,
loop: false,
format: (d) => ""
})
Insert cell
limits
Insert cell
curDate = md`# ${textcolor(timeFormat(new Date(time1)), "black")}`
Insert cell
leg = {
return colorView === "Anomaly"
? Plot.legend({
marginLeft: 10,
marginRight: 10,

style: {
backgroundColor: "#000000",
color: "#e0f5ee",
fontSize: "16px",
fontWeight: "normal"
},
color: {
type: "diverging",
domain: [-4, 4],
pivot: 0,
reverse: true,
legend: true,
label: "SSTA (°C) →"
}
})
: Plot.legend({
color: {
type: "categorical",
domain: ["Moderate", "Strong", "Severe", "Extreme"],
range: ["#FEDB67", "#f26722", "#cd3728", "#7E1416"] // use the "accent" scheme
},
style: {
backgroundColor: "#000000",
color: "#e0f5ee",
fontSize: "16px",
fontWeight: "normal"
}
});
}
Insert cell
Plot.legend({
style: {
fontSize: "16px",
backgroundColor: "#000000",
color: "#e0f5ee"
},
color: {
type: "categorical",
domain: ["Moderate", "Strong", "Severe", "Extreme"],
range: ["#FEDB67", "#f26722", "#cd3728", "#7E1416"] // use the "accent" scheme
}
})
Insert cell
// new Date(time1)
Insert cell
mutable siteClicked = 8
Insert cell
viewof lineChart = {
const HWlineChart = Plot.plot({
style: {
backgroundColor: "#000000",
color: "#e0f5ee",

// fontFamily: "system-ui",
fontSize: 20
// title: "stuff"
// overflow: "visible"
},
// height: "auto",
// height: 400,
marginTop: 50,
className: "hwclass",

marks: [
Plot.line(clickedSite, {
x: "date",
y: "sst",
stroke: colors.get("sst"),

curve: "step",
strokeWidth: 2
}),
Plot.line(clickedSite, {
x: "date",
y: "thresh",
stroke: colors.get("thresh"),
opacity: 0.7,
// curve: "step",
strokeWidth: 2
}),
Plot.line(clickedSite, {
x: "date",
y: "seas",
stroke: colors.get("seas"),
opacity: 0.7,
// curve: "step",
strokeWidth: 2
}),
Plot.areaY(clickedSite, {
x: "date",
y1: "thresh",
y2: "diff",
sort: "date",
curve: "step",
fill: colors.get("moderate")
}),

Plot.areaY(clickedSite, {
x: "date",
y1: "thresh",
y2: "diffStrong",
sort: "date",
curve: "step",
fill: colors.get("Strong")
}),
Plot.areaY(clickedSite, {
x: "date",
y1: "thresh",
y2: "diffExtreme",
sort: "date",
curve: "step",
fill: colors.get("Extreme")
}),

Plot.areaY(clickedSite, {
x: "date",
y1: "thresh",
y2: "diffSevere",
sort: "date",
curve: "step",
fill: colors.get("Severe")
}),

// rule at bottom of chart marking y=0;
Plot.ruleY([0]),

// vertical rule to mark date/time of event
Plot.ruleX([time1], {
stroke: "gray",
y1: 0,
y2: d3.max(clickedSite, (d) => d.sst)
}),
Plot.text(
[
{
x: dateForLabel,
y: yValueForLabel,
text: buoyClicked
}
],
{
x: "x",
y: "y",
text: "text",
fontSize: 24
}
)
],

color: {
domain: ["above", "below", "avg", "thresh"],
range: [
colors.get("above"),
colors.get("below"),
colors.get("actuals"),
colors.get("forecast")
]
// legend: true
},
y: {
label: "↑ (°C)"
},

marginLeft: 60,
width: 500,
height: 300
});

const SSTAlineChart = Plot.plot({
x: {
domain: [limitsDelayed[0], limitsDelayed[1]]
},
y: {
label: "↑ SST (°C)",
domain: [0, yMaxDomainToUse]
},
style: {
backgroundColor: "#000000",
color: "#e0f5ee",
// fontFamily: "system-ui",
fontSize: 20
// overflow: "visible"
},
height: 500,
marginTop: 50,
className: "hwclass",
// y: {
// nice: true
// },
// x: {
// nice: true
// },
marks: [
Plot.dot(clickedSite, {
x: "date",
y: "sst",
stroke: "ssta",
fill: "ssta"
}),
Plot.line(clickedSite, {
x: "date",
y: "sst",
stroke: "#ccc",
curve: "step",
strokeWidth: 0.5
}),
// vertical rule to mark date/time of event
Plot.ruleX([time1], {
stroke: "white",
y1: 0,
y2: d3.max(clickedSite, (d) => d.sst)
}),
Plot.text(
[
{
x: dateForLabel,
y: yValueForLabel,
text: buoyClicked
}
],
{
x: "x",
y: "y",
text: "text",
fontSize: 24
}
)
],
color: {
type: "diverging",
domain: [-4, 4],
pivot: 0,
reverse: true
// legend: true,
// label: "SSTA (°C) →"
},

width: 500,
height: 300
// marginBottom: 70,
// label: buoyClicked
// title: "some stie"
});
if (siteClicked !== null) {
return colorView === "Anomaly" ? SSTAlineChart : HWlineChart;
} else {
return md``;
}
}
Insert cell
width
Insert cell
clickedSite.length
Insert cell
d3.max(clickedSite, (d) => d.sst) * 1.1
Insert cell
Insert cell
buoys
Insert cell
yMaxDomainToUse = {
return clickedSite[Math.floor(clickedSite.length / 1.2)] === undefined ?
18 : d3.max(clickedSite, (d) => d.sst) * 1.1
}
Insert cell
yValueForLabel = {
return clickedSite[Math.floor(clickedSite.length / 1.2)] === undefined
? 18
: d3.max(clickedSite, (d) => d.sst) * 1.1;
}
Insert cell
dateForLabel = {
return clickedSite[Math.floor(clickedSite.length / 1.2)] === undefined
? d3.timeDay.offset(limitsDelayed[0], 30)
: clickedSite[Math.floor(clickedSite.length * 0.2)].date;
}
Insert cell
Math.floor(clickedSite.length * 0.1)
Insert cell
buoyClicked = buoys.find((d) => d.pk === siteClicked).long_name
Insert cell
Insert cell
viewof table = Inputs.table(clickedSite, {})
Insert cell
clickedSite = buoyDailyData.filter((d) => d.station === siteClicked)
Insert cell
sstaColors = d3.scaleSequential(d3.interpolateRdBu).domain([4, -4])
Insert cell
coloursForSSTA = clickedSite.map((d) => sstaColors(d.ssta))
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
r = "mapbox://styles/hakai/ckwpei0yq08cj15nthgd4ql45" //"mapbox://styles/hakai/ckwuxmze164c314pe8hs0s1on" //"mapbox://styles/hakai/ckwpei0yq08cj15nthgd4ql45" //"mapbox://styles/mapbox/dark-v10" //mapbox://styles/hakai/ckwp8ahbx2u0w15o5zwx3odtn"
Insert cell
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
Insert cell
buoyDailyData
Insert cell
// selected = hexbyLocation.get(
// map.selected ? map.selected.data.lng + "|" + map.selected.data.lat : ""
// ) || []
Insert cell
// hexbyLocation = d3.group(hex, (d) => d.lng + "|" + d.lat)
Insert cell
// HWStatus.filter((d) => d.station === "7")
Insert cell
new Date(time1).toISOString().substring(0, 10) === "2021-01-01"
Insert cell
HWsForDate = buoyDailyData.filter(
(d) =>
new Date(time1).toISOString().substring(0, 10) ===
new Date(d.result_time).toISOString().substring(0, 10)
)
Insert cell
buoyDailyData.filter((d) => d.category === "Strong")
Insert cell
new Date(dateExtent[1])
Insert cell
center = projection.invert([width/2, height/2])
Insert cell
metersToPixelsAtMaxZoom = (meters, latitude) =>
meters / 0.075 / Math.cos(latitude * Math.PI / 180)
Insert cell
limits[0]
Insert cell
dayBeforeStart = {
const b = Object.assign(limits[0]);
const fistDate = new Date(b);

return new Date(fistDate.setDate(fistDate.getDate() - 1))
.toISOString()
.substring(0, 10);
}
Insert cell
limits[0]
Insert cell
// buoyDailyData = {
// const buoyDailyData = await FileAttachment(
// "buoysHWStatusDaily-2.json"
// ).json();
// buoyDailyData.forEach((d) => {
// d.ssta = d.sst - d.seas;
// d.diffStrong = d.thresh;
// d.diffExtreme = d.thresh;
// d.diffSevere = d.thresh;
// if (d.category === "Strong") {
// d.diffStrong = Math.max(d.thresh, d.sst);
// }
// if (d.category === "Extreme") {
// d.diffExtreme = Math.max(d.thresh, d.sst);
// }
// if (d.category === "Severe") {
// d.diffSevere = Math.max(d.thresh, d.sst);
// }
// d.diff = Math.max(d.thresh, d.sst);
// d.date = new Date(d.result_time);
// });
// let outdate = buoyDailyData.filter(
// (d) =>
// new Date(limits[0].toISOString().substring(0, 10)) <= d.date &&
// new Date(limits[1].toISOString().substring(0, 10)) >= d.date
// );
// return outdate;
// }
Insert cell
limits
Insert cell
dayBeforeStart
Insert cell
buoyDailyData = {
// let daysago = new Date().getDate() - 7;
// let st = new Date(new Date().setDate(daysago));

return fetch(
"https://t6r95rekqe.execute-api.us-east-1.amazonaws.com/dev/getDailySSTStats?startDate=" +
dayBeforeStart +
"&endDate=" +
limitsDelayed[1].toISOString().substring(0, 10) +
""
)
.then((resp) => resp.json())
.then((data) => {
data.forEach((d) => {
d.ssta = d.sst - d.seas;
d.diff = d.thresh;
d.diffStrong = d.thresh;
d.diffExtreme = d.thresh;
d.diffSevere = d.thresh;
if (d.category === "Strong") {
d.diffStrong = Math.max(d.thresh, d.sst);
}
if (d.category === "Extreme") {
d.diffExtreme = Math.max(d.thresh, d.sst);
}
if (d.category === "Severe") {
d.diffSevere = Math.max(d.thresh, d.sst);
}
if (d.category === "Moderate") {
d.diff = Math.max(d.thresh, d.sst);
}
// d.diff = Math.max(d.thresh, d.sst);
d.date = new Date(d.result_time);
});
return data;
});
}
Insert cell
// dateExtent[0].toISOString().substring(0, 10)
Insert cell
// updateMapbox = {
// // This allows us to update the map with data without re-rendering the whole cell
// // There is a bit of weirdness around adding and removing the layer to make sure mapbox rerenders
// let fc = {
// type: "FeatureCollection",
// features: hexgeo
// };
// if (map._loaded) {
// if (!map.getSource("hexbins")) {
// map.addSource("hexbins", {
// type: "geojson",
// data: fc
// });
// } else {
// // console.log("setting source")
// map.getSource("hexbins").setData(fc);
// }
// if (map.getLayer(hexbinLayer.id)) {
// map.removeLayer(hexbinLayer.id);
// }
// // console.log("adding layer")
// map.addLayer(hexbinLayer);
// // map.flyTo(projection.invert([100,1000]))
// // console.log("flying")
// // }
// return true;
// }
// return false;
// }
Insert cell
// map._loaded
Insert cell
// map.getSource("hexbins")
Insert cell
// import {california, countyShapes} with {height as height, hexbin as hexbin} from "@enjalot/air-quality-explorations"
Insert cell
originalScale = 25355.18980109889
Insert cell
scaleRatio = projection.scale() / originalScale
Insert cell
widthRatio = width / 955
Insert cell
heightRatio = height / 500
Insert cell
projection = d3
.geoAlbers()
.rotate([126, 0])
.fitSize(
[width, height],
topojson.feature(BC_Midres, BC_Midres.objects.BC_Midres_latlng)
)
Insert cell
pixelRadius = 100 * scaleRatio * d3.min([widthRatio, heightRatio])
Insert cell
hexbin = d3
.hexbin()
.extent([
[0, 0],
[width, height]
])
.radius(100)
Insert cell
numOfDates = d3.timeDay.count(...dateExtent)
Insert cell
height = 500
Insert cell
colorMHW = d3
.scaleOrdinal()
.domain(["none", "Moderate", "Strong", "Extreme", "Severe"])
.range(["#31a354", "#FEDB67", "#f26722", "#7E1416", "#cd3728"])
Insert cell
opacityMHW("none")
Insert cell
opacityMHW = d3
.scaleOrdinal()
.domain(["none", "Moderate", "Strong", "Extreme", "Severe"])
// .range([0.9, 0.9, 0.9, 0.9, 0.9])
Insert cell
colorPM1 = d3.scaleLinear()
.domain([0,50, 100, 150, 200, 250])
.range(["green", "yellow", "orange", "red", "maroon", "maroon"])
Insert cell
opacityPM1 = d3.scaleLinear()
.domain([0,50, 100, 150, 200, 250])
.range([0.1, 0.5, 0.9, 0.9, 0.9, 0.9])
Insert cell
colorP03 = d3.scaleLinear()
.domain([1,1000, 5000, 10000, 20000, 25000])
.range(["green", "yellow", "orange", "red", "maroon", "maroon"])
Insert cell
opacityP03 = d3
.scaleLinear()
.domain([1, 1000, 5000, 10000, 20000, 25000])
.range([0.1, 0.75, 0.75, 0.9, 0.9, 0.9])
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.0.0-rc.3", "d3-hexbin@0.2")
Insert cell
// token = "pk.eyJ1IjoiaGFrYWkiLCJhIjoiY2lyNTcwYzY5MDAwZWc3bm5ubTdzOWtzaiJ9.6QhxH6sQEgK634qO7a8MoQ"
Insert cell
// mapboxgl = {
// const gl = await require("mapbox-gl");
// if (!gl.accessToken) {
// gl.accessToken =
// "pk.eyJ1IjoiaGFrYWkiLCJhIjoiY2lyNTcwYzY5MDAwZWc3bm5ubTdzOWtzaiJ9.6QhxH6sQEgK634qO7a8MoQ";
// const href = await require.resolve("mapbox-gl/dist/mapbox-gl.css");
// document.head.appendChild(html`<link href=${href} rel=stylesheet>`);
// }
// return gl;
// }
Insert cell
import { textcolor } from "@observablehq/text-color-annotations-in-markdown"
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
// import { brushFilterX } from "921d584bd92a9817"
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