149 lines
4.2 KiB
Typst
149 lines
4.2 KiB
Typst
#import "@preview/lilaq:0.6.0" as lq
|
|
|
|
#let epoch = datetime(year: 1970, month: 01, day: 01, hour: 0, minute: 0, second: 0)
|
|
#let unix-to-datetime(stamp) = epoch + duration(seconds: int(stamp))
|
|
#let datetime-to-unix(dt) = int((dt - epoch).seconds())
|
|
|
|
#let parse-iso-datetime(s) = {
|
|
let parts = s.split("T")
|
|
let date-part = parts.at(0).split("-").map(int)
|
|
let time-part = parts.at(1).split(":").map(int)
|
|
datetime(
|
|
year: date-part.at(0),
|
|
month: date-part.at(1),
|
|
day: date-part.at(2),
|
|
hour: time-part.at(0),
|
|
minute: time-part.at(1),
|
|
second: time-part.at(2)
|
|
)
|
|
}
|
|
|
|
#let window-regions(filtered-windows, filtered-times-dt) = {
|
|
let regions = ()
|
|
let i = 0
|
|
while i < filtered-windows.len() {
|
|
let start-time = filtered-times-dt.at(i)
|
|
let status = filtered-windows.at(i)
|
|
let j = i
|
|
// Find end of consecutive region with same status
|
|
while j < filtered-windows.len() and filtered-windows.at(j) == status {
|
|
j += 1
|
|
}
|
|
let end-time = if j < filtered-times-dt.len() {
|
|
filtered-times-dt.at(j - 1)
|
|
} else {
|
|
filtered-times-dt.at(filtered-times-dt.len() - 1)
|
|
}
|
|
// Add small duration to end time to make rectangle visible
|
|
let end-time-dt = end-time + duration(seconds: 60)
|
|
|
|
let fill-color = if status == 0 { none } else { rgb("#e8e8e8") }
|
|
|
|
regions.push(lq.rect(
|
|
start-time,
|
|
0%,
|
|
width: end-time-dt - start-time,
|
|
height: 100%,
|
|
fill: fill-color,
|
|
stroke: none,
|
|
z-index: 1
|
|
))
|
|
|
|
i = j
|
|
}
|
|
regions
|
|
}
|
|
|
|
#let plot_co2(path, start-date, stop-date) = [
|
|
#let start-unix = datetime-to-unix(start-date)
|
|
#let stop-unix = datetime-to-unix(stop-date)
|
|
|
|
#let data = lq.load-txt(
|
|
read(path),
|
|
header: true,
|
|
converters: (time: parse-iso-datetime, rest: float)
|
|
)
|
|
#let times = data.at("time")
|
|
#let co2s = data.at("co2")
|
|
#let windows = data.at("windows")
|
|
|
|
// Filter data by date range
|
|
#let filtered-indices = range(times.len()).filter(i => {
|
|
let t = times.at(i)
|
|
t >= start-date and t <= stop-date
|
|
})
|
|
|
|
#let filtered-times-dt = filtered-indices.map(i => times.at(i))
|
|
#let filtered-co2s = filtered-indices.map(i => co2s.at(i))
|
|
#let filtered-windows = filtered-indices.map(i => windows.at(i))
|
|
#let regions = window-regions(filtered-windows, filtered-times-dt)
|
|
|
|
#lq.diagram(
|
|
width: 100%,
|
|
height: 7cm,
|
|
title: [CO2 Level over Time],
|
|
xlabel: [Time],
|
|
ylabel: [CO2 Level (ppm)],
|
|
yaxis: (lim: (400, 1500), exponent: 0),
|
|
xaxis: (format-ticks: lq.tick-format.datetime.with(
|
|
format-offset: (datetimes, period: none) => none,
|
|
)),
|
|
..regions,
|
|
lq.plot(filtered-times-dt, filtered-co2s, label: [CO2 Level], color: rgb("#388e3c"))
|
|
)
|
|
]
|
|
|
|
#let plot_temp_hum(path, start-date, stop-date) = [
|
|
#let start-unix = datetime-to-unix(start-date)
|
|
#let stop-unix = datetime-to-unix(stop-date)
|
|
|
|
#let data = lq.load-txt(
|
|
read(path),
|
|
header: true,
|
|
converters: (time: parse-iso-datetime, rest: float)
|
|
)
|
|
#let times = data.at("time")
|
|
#let temps = data.at("temperature")
|
|
#let hums = data.at("humidity")
|
|
#let windows = data.at("windows")
|
|
|
|
|
|
// Filter data by date range
|
|
#let filtered-indices = range(times.len()).filter(i => {
|
|
let t = times.at(i)
|
|
t >= start-date and t <= stop-date
|
|
})
|
|
|
|
#let filtered-times-dt = filtered-indices.map(i => times.at(i))
|
|
#let filtered-temps = filtered-indices.map(i => temps.at(i))
|
|
#let filtered-hums = filtered-indices.map(i => hums.at(i))
|
|
#let filtered-times-dt = filtered-indices.map(i => times.at(i))
|
|
#let filtered-windows = filtered-indices.map(i => windows.at(i))
|
|
#let regions = window-regions(filtered-windows, filtered-times-dt)
|
|
|
|
#lq.diagram(
|
|
width: 100%,
|
|
height: 7cm,
|
|
title: [Temperature and Humidity over Time],
|
|
xlabel: [Time],
|
|
ylabel: [Temperature (°C)],
|
|
yaxis: (lim: (20, 35)),
|
|
xaxis: (format-ticks: lq.tick-format.datetime.with(
|
|
format-offset: (datetimes, period: none) => none,
|
|
)),
|
|
..regions,
|
|
lq.plot(filtered-times-dt, filtered-temps, label: [Temperature], color: rgb("#d32f2f")),
|
|
lq.yaxis(
|
|
position: right,
|
|
label: [Humidity (%)],
|
|
lim: (30, 55),
|
|
lq.plot(filtered-times-dt, filtered-hums, label: [Humidity], color: rgb("#1976d2"))
|
|
)
|
|
)
|
|
]
|
|
|
|
|
|
|
|
|
|
|