Published
Edited
Aug 26, 2021
Importers
17 stars
Insert cell
Insert cell
Plot.line(data, Plot.windowY({ x: "date", y: "kwh", k: 7, curve: "step" })).plot({
grid: true
})
Insert cell
Insert cell
Insert cell
Plot.line(data, Plot.windowY({ x: "date", y: "money", k: 7, curve: "step"})).plot({
grid: true
})
Insert cell
Insert cell
Plot.line(data, Plot.windowY({ x: "date", y: d => d.money/d.kwh * 100, k: 1, curve: "step" })).plot({
grid: true,
// marks: [ Plot.ruleY([0]) ],
y: {
label: "↑ cents per kWh"
},
})
Insert cell
Insert cell
Insert cell
addTooltips(Plot.rectY(data, { x1: "date", x2: d => d3.utcDay.offset(d.date), y: "kwh", title: tip, inset: 1 }).plot({
y: { grid: false },
x: {
tickRotate: 90,
tickFormat: d => timeFormat(d),
},
marginLeft: 30,
marginBottom: 100,
width: width,
style: {
fontSize: "8px"
}
}))
Insert cell
Insert cell
Plot.plot({
marks: [
Plot.rectY(data, { x1: "date", x2: d => d3.utcDay.offset(d.date), y: "kwh", title: tip, inset: 1, fill: weekendColor }),
Plot.link(data, Plot.binX({y1: "mean", y2: "mean" }, { x: "date", y: "kwh", stroke: "blue", thresholds: d3.timeMonth })),
Plot.line(data, Plot.windowY({ x: "date", y: "kwh", k: 7, stroke: "orange", curve: "step" }))
],
y: { grid: true },
x: {
tickRotate: 90,
tickFormat: d => timeFormat(d),
},
color: { ...weekendColorOptions },
marginLeft: 30,
marginBottom: 100,
width: width,
style: {
fontSize: "9px"
}
})
Insert cell
Insert cell
Plot.barY(data, { x: dayOfMonth, y: "kwh", fill: weekendColor }).plot({
facet: {
data,
x: d => d.date.getMonth(),
},
y: { grid: true },
x: {
tickRotate: 90,
},
fx: {
tickFormat: d => Plot.formatMonth()(d),
},
color: { ...weekendColorOptions },
marginLeft: 30,
marginBottom: 100,
width: width,
style: {
fontSize: "8px"
}
})
Insert cell
Insert cell
Insert cell
Insert cell
tip = d => `${dateFormat(d.date)} (${Plot.formatWeekday()(d.date.getDay())}): ${d.kwh}`
Insert cell
Magical moment! Just change from bar to do... and it all works.
Insert cell
can we color by >average and below average for the month?
Insert cell
weekendColor = d => d.date.getDay()%6 == 0 ? "weekend" : "weekday"
Insert cell
weekendColorOptions = ({
domain: ["weekend", "weekday"],
range: ["lightgray", "gray"],
})
Insert cell
dayOfMonth = d => d.date.getDate()
Insert cell
timeFormat = d3.timeFormat("%m/%d")
Insert cell
Insert cell
Insert cell
Insert cell
Plot.plot({
marks: [
Plot.rectY(data, {
x1: "date",
x2: (d) => d3.utcDay.offset(d.date),
y: "kwh",
title: tip,
inset: 1,
fill: weekendColor
}),
// show only above the moving avearge so the visible bars show a diff between that day's value & moving average; and days below the moving average are not shown -- joy! the power of the white rectangle ;)
Plot.rectY(
data,
Plot.windowY({
x1: "date",
x2: (d) => d3.utcDay.offset(d.date),
y: "kwh",
title: tip,
inset: 1,
fill: "white",
k: 7
})
)
// Plot.line(data, Plot.windowY({ x: "date", y: "kwh", k: 7, stroke: "#eee" })),
],
y: { grid: false },
x: {
tickRotate: 90,
tickFormat: (d) => timeFormat(d)
},
color: { ...weekendColorOptions },
marginLeft: 30,
marginBottom: 100,
width: width,
style: {
fontSize: "8px"
}
})
Insert cell
Insert cell
movingAvg = Plot.line(data, Plot.windowY({ x: "date", y: "kwh", k: 7, shift: "trailing" }))
.initialize()
.channels
.find(([channel]) => channel === "y")[1].value
Insert cell
addTooltips(Plot.plot({
marks: [
Plot.ruleY([0]),
Plot.rectY(data, {
x1: "date",
x2: (d) => d3.utcDay.offset(d.date),
inset: 1,
y1: (d,i) => movingAvg[i] || 0,
y2: (d,i) => d.kwh > movingAvg[i] + 5 ? d.kwh : movingAvg[i],
fill: weekendColor,
title: tip
}),
Plot.line(data, Plot.windowY({ x: "date", y: "kwh", k: 7, stroke: "#eee", curve: "step", shift: "trailing" })),
],
y: { grid: false },
x: {
// grid: true,
tickRotate: 90,
tickFormat: d => timeFormat(d),
},
color: { ...weekendColorOptions },
marginLeft: 30,
marginBottom: 100,
width: width,
style: {
fontSize: "9px"
}
}))
Insert cell
Insert cell
addTooltips(Plot.dot(data, { x: "date", y: "kwh", title: tip, fill: 'grey'}).plot({
y: { grid: false },
x: {
tickRotate: 90,
tickFormat: d => timeFormat(d),
},
marks: [
Plot.frame()
],
marginLeft: 30,
marginBottom: 100,
width: width,
style: {
fontSize: "9px"
}
}))
Insert cell
Insert cell
Plot.dot(data, { x: "date", y: "kwh", fill: "gray" }).plot({
marks: [
Plot.line(data, Plot.windowY({ x: "date", y: "kwh", k: 7, stroke: "orange", shift: "centered" })), // centered is by default
//Plot.link(data, Plot.binX({y1: "mean", y2: "mean" }, { x: "date", y: "kwh", stroke: "blue", thresholds: d3.timeMonth })),
Plot.frame()
],
x: {
tickRotate: 90,
tickFormat: d => timeFormat(d),
},
marginLeft: 30,
marginBottom: 100,
width: width,
style: {
fontSize: "9px"
}
})
Insert cell
Insert cell
addTooltips(
Plot.dot(
data, {
x: "date",
y: "kwh",
title: tip,
fill: (d,i) => d.kwh > movingAvg[i] + 5 ? 1: 0 // adding 5 since we want to highlight points that are a least a bit *above* the moving average
})
.plot({
y: { grid: false },
x: {
tickRotate: 90,
tickFormat: d => timeFormat(d),
},
marks: [
Plot.ruleY([0]),
Plot.line(data, Plot.windowY({ x: "date", y: d => d.kwh + 5, k: 7, stroke: "lightgray", shift: "trailing" }))
],
marginLeft: 30,
marginBottom: 100,
marginRight: 50,
width: width,
color: {
range: ["steelblue", "orange"]
},
}))
Insert cell
finalviz = addTooltips(
Plot.dot(data, {
x: "date",
y: "kwh",
title: tip,
fill: (d, i) => (d.kwh > movingAvg[i] + 5 ? 1 : 0) // adding 5 since we want to highlight points that are a least a bit *above* the moving average
}).plot({
y: { grid: false },
x: {
tickRotate: 90,
tickFormat: (d) => timeFormat(d)
},
marks: [
Plot.ruleY([0]),
Plot.ruleX(data, { x: "date", y: "kwh", stroke: "#eee", strokeWidth: 3, title: tip }),
Plot.line(
data,
Plot.windowY({
x: "date",
y: (d) => d.kwh + 5,
k: 7,
stroke: "lightgray",
shift: "trailing"
})
)
],
marginLeft: 30,
marginBottom: 100,
marginRight: 50,
width: width,
color: {
range: ["steelblue", "orange"]
}
})
)
Insert cell
Insert cell
Insert cell
Plot.plot({
// width: 300,
height: 180,
x: {
tickFormat: i => "SMTWTFS"[i],
tickSize: 0
},
y: { axis: null },
fx: {
tickFormat: d => Plot.formatMonth()(d),
},
color: {
scheme: "oranges",
},
facet: {
data: data,
y: d => d.date.getUTCFullYear(),
x: d => d.date.getUTCMonth(),
},
marks: [
Plot.cell(data, {
y: d => d3.timeMonday.count(d3.utcMonth(d.date), d.date), // monday-based layout
x: d => d.date.getUTCDay(),
fill: "kwh",
inset: 0,
})
]
})
Insert cell
Insert cell
Plot.barX(data, Plot.binY({x: "count"}, { y: "kwh", thresholds: 10 })).plot({
facet: {
data,
x: d => d.date.getMonth()
},
y: { grid: true },
fx: {
tickFormat: d => Plot.formatMonth()(d)
},
marginLeft: 30,
marginBottom: 100,
width: width,
style: {
fontSize: "9px"
}
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
data = money
.filter(d => d["High Temp"] !== "N/A") // remove empty days
.map((d, i) => {
return {
date: new Date(d.Date),
money: +d["Daily Cost"],
kwh: +kwh[i]["Daily Cost"]
};
})
Insert cell
// want to be sure there aren't duplicate dates.
// this should have the same # of elements as the data array
new Set(data.map(d => d.date))
Insert cell
Insert cell
files = [
{
month: "march",
kwh: FileAttachment("kwh-march.xlsx"),
electric: FileAttachment("electric-march.xlsx")
},
{
month: "april",
kwh: FileAttachment("kwh-april.xlsx"),
electric: FileAttachment("electric-april.xlsx")
},
{
month: "may",
kwh: FileAttachment("kwh-may.xlsx"),
electric: FileAttachment("electric-may.xlsx")
},
{
month: "june",
kwh: FileAttachment("kwh-june.xlsx"),
electric: FileAttachment("electric-june.xlsx")
},
{
// this has "july@1" because i replaced an earlier upload with a new one, so this pulls the new one from the file attachment
month: "july@1",
kwh: FileAttachment("kwh-july@1.xlsx"),
electric: FileAttachment("electric-july@1.xlsx")
}
]
Insert cell
months = files.map(d => d.month)
Insert cell
kwhsheets = files.map(f => readxlsx(f.kwh).then(d => d.json()))
Insert cell
kwh = Promise.all(
files.map(f => readxlsx(f.kwh)
.then(d => d.json())
.then(d => d.get("Sheet1")))
).then(d => d.flat())
Insert cell
kwh[150]
Insert cell
moneysheets = files.map(f => readxlsx(f.electric).then(d => d.json()))
Insert cell
money = {
let sheets = []
let data;
for(let sheet of moneysheets) {
data = await sheet
sheets = sheets.concat(data.get("Sheet1"))
yield sheets
}
}
Insert cell
dateFormat = d3.timeFormat("%Y-%m-%d")
Insert cell
dateFormat(new Date())
Insert cell
Insert cell
import {readxlsx} from "@fil/xlsx"
Insert cell
import {addTooltips} from "@mkfreeman/plot-tooltip"
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