Public
Edited
Mar 24, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof limits = brushFilterX(
d3.extent(data, (d) => d.date),
{ defaultExtent: [d3.isoParse("2020-02-01"), d3.isoParse("2020-10-10")] }
)
Insert cell
// Create a line plot showing the rolling average
Plot.line(
data,
// compute the rolling average, show values in the brush selection
Plot.windowY({
x: d => (!limits || d.date >= limits[0] && d.date <= limits[1]) ? d.date : NaN,
y: "value",
k: smooth
})
).plot({
marks: [Plot.ruleY([0])], // draw a line at x=0
marginLeft: 50,
x: { label: "date (utc)→", domain: limits || undefined },
y: {// Filtering down based on the brush
label: "↑ Electricity Demand (MWh)",
domain: [0, d3.max(data, (d) => d.value)]
},
width,
height: 400,
caption: md`<em>Note, this displays the x-axis in UTC time, not the local time for California.</em>`
})
Insert cell
viewof limits
Insert cell
data
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// Extract the desired information from each timestamp
data = raw_data.map((d) => {
const tzdate = Temporal.Instant.from(d.date).toZonedDateTimeISO(
"America/Los_Angeles"
); // date in localized timezone
const date = new Date(tzdate.epochMilliseconds); // Javascript Date object, stores date in browser's local timezone
const hour = tzdate.hour;
const dayOfMonth = tzdate.day;
const day = weekdays[tzdate.dayOfWeek + -1];
const weekend = tzdate.dayOfWeek > 5 ? "Weekend" : "Weekday";
const week = tzdate.weekOfYear;
const month = months[tzdate.month - 1];
const quarter =
tzdate.month < 4
? "Q1: Jan - Mar"
: tzdate.month < 7
? "Q2: Apr - Jun"
: tzdate.month < 10
? "Q3: Jul - Sep"
: "Q4: Oct - Dec";
const value = d.value;
return {
date,
hour,
day,
weekend,
week,
month,
quarter,
value,
dayOfMonth,
};
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
data[0]
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import {brushFilterX} from "@observablehq/brush-filter-x"
Insert cell
import {addTooltips} from "@mkfreeman/plot-tooltip"
Insert cell
import {authorship, readMore, navigation, workshop} from "@observablehq/timeseries-assets"
Insert cell
// Options for breaking the charts into different facets
facet_options = new Map(["Hour", "Day", "Weekend", "Week", "Month", "Quarter", "None"].map(d => [d, d.toLowerCase()]))
Insert cell
// Labels on hover
get_title = (d) => {
// Compute average
const avg = d3.format(",.0f")(d3.mean(d, (d) => d.value));
const x_value = x_facet === "hour" ? d[0].hour + ":00 PST" : d[0][x_facet]
const y_value = y_facet === "hour" ? d[0].hour + ":00 PST" : d[0][y_facet]
return `Avg. Demand: ${avg} MWh \n` +
(x_facet == 'none' ? "" : `${capitalize(x_facet)}: ${x_value}\n `) +
(y_facet == "none" ? "" : `${capitalize(y_facet)}: ${y_value}`);
}
Insert cell
// Label for hours
label_hour = (d) => d === "hour" ? ":00 PST" : ""
Insert cell
// Setting the domain and tick format depending on the facet
get_facet_options = (facet, direction = "x") => facet === "day"
? { domain: weekdays, tickFormat:d => (direction === "x" && width < 600) ?d.slice(0, 1) :d}
: facet === "month"
? { domain: months, tickFormat: d => (direction === "x" && width < 600) ? d.slice(0, 1) : d }
: (facet === "hour" && width > 800) ? {tickFormat: d => d + ":00"}:{}

Insert cell
// Capitalize: https://stackoverflow.com/questions/1026069/how-do-i-make-the-first-letter-of-a-string-uppercase-in-javascript
capitalize = (string) => {
return string.charAt(0).toUpperCase() + string.slice(1);
}
Insert cell
months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
Insert cell
weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
Insert cell
// Load the Temporal API using a Polyfill
Temporal = {
const TemporalLib = await require("@js-temporal/polyfill@0.3.0")
return TemporalLib.Temporal
}
Insert cell
<!-- Style for plots with captions -->
<style>
figure {
max-width:none;
}
/* prevent tooltips on ticks */
.plot line {
pointer-events: none;
}
</style>
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