|
1 | 1 | ^{:kindly/hide-code true |
2 | | - :clay {:title "Getting Started with tablecloth.time" |
| 2 | + :clay {:title "Relaunch tablecloth.time: Composability over Abstraction" |
3 | 3 | :quarto {:author [:ezmiller] |
4 | 4 | :description "A composable approach to time series analysis in Clojure" |
5 | 5 | :draft false |
6 | 6 | :type :post |
7 | 7 | :date "2026-03-27" |
8 | 8 | :category :clojure |
9 | 9 | :tags [:time-series :tablecloth :data-science]}}} |
10 | | -(ns time-series.tablecloth-time |
| 10 | +(ns ezmiller.relaunching-tablecloth-time |
11 | 11 | (:require [tablecloth.api :as tc] |
12 | 12 | [tablecloth.time.api :as tct] |
13 | 13 | [scicloj.tableplot.v1.plotly :as plotly] |
14 | 14 | [tech.v3.datatype.functional :as dfn] |
15 | 15 | [scicloj.kindly.v4.kind :as kind])) |
16 | 16 |
|
17 | | -;; [tablecloth.time](https://github.com/scicloj/tablecloth.time) is a composable |
| 17 | +^{:kindly/hide-code true} |
| 18 | +(kind/html "<figure> |
| 19 | + <img src=\"vic_elec_yearly.png\" alt=\"Victoria electricity demand by day of year, colored by year\" style=\"width:100%\"/> |
| 20 | + <figcaption>Half-hourly electricity demand in Victoria, Australia (2012–2014). Each line is one day, phased over the time of day (0 = midnight, 1 = midnight). Colors indicate year.</figcaption> |
| 21 | +</figure>") |
| 22 | + |
| 23 | +;; I recently relaunched an old Scicloj project called [tablecloth.time](https://github.com/scicloj/tablecloth.time). The goal of this project was to build a composable |
18 | 24 | ;; extension for time series analysis built on top of |
19 | | -;; [tablecloth](https://scicloj.github.io/tablecloth/). This post walks through |
20 | | -;; its core primitives using the classic Victoria electricity demand dataset. |
| 25 | +;; [tablecloth](https://scicloj.github.io/tablecloth/). Originally, we |
| 26 | +;; had built this project around a dataset index mechanism that was |
| 27 | +;; built into tech.ml.dataset, but after that feature was removed in |
| 28 | +;; v7, the project required a rethink. This post walks through that |
| 29 | +;; rethink and the projects core core primitives today using the |
| 30 | +;; Victoria electricity demand dataset. |
21 | 31 |
|
22 | 32 | ;; ## Design Philosophy |
23 | 33 | ;; |
|
42 | 52 | ;; Australia, spanning 2012-2014. Let's load it and take a look. |
43 | 53 |
|
44 | 54 | (def vic-elec |
45 | | - (-> (tc/dataset "https://raw.githubusercontent.com/scicloj/tablecloth.time/main/data/vic_elec.csv" |
| 55 | + (-> (tc/dataset "https://gist.githubusercontent.com/ezmiller/6edf3e0f41848f532436c15bc94c2f4d/raw/vic_elec.csv" |
46 | 56 | {:key-fn keyword}) |
47 | | - (tc/convert-types :Time :instant))) |
| 57 | + (tc/convert-types :Time :local-date-time))) |
48 | 58 |
|
49 | 59 | (tc/head vic-elec) |
50 | 60 |
|
|
110 | 120 | (-> vic-elec |
111 | 121 | (tct/add-lag :Demand 48 :Demand_lag48) |
112 | 122 | (tc/drop-missing) |
113 | | - (plotly/layer-point {:=x :Demand_lag48 |
| 123 | + (plotly/layer-point {:=x :Demand_lag48 |
114 | 124 | :=y :Demand |
115 | 125 | :=mark-opacity 0.3})) |
116 | 126 |
|
|
123 | 133 | ;; is a composable pattern: extract the time component you want, group by it, |
124 | 134 | ;; and aggregate. |
125 | 135 | ;; |
126 | | -;; Daily averages: |
| 136 | +;; Daily averages (grouping by year, month, and day): |
127 | 137 |
|
128 | 138 | (-> vic-elec |
129 | | - (tct/add-time-columns :Time [:date]) |
130 | | - (tc/group-by [:date]) |
| 139 | + (tct/add-time-columns :Time [:year :month :day]) |
| 140 | + (tc/group-by [:year :month :day]) |
131 | 141 | (tc/aggregate {:Demand #(dfn/mean (:Demand %)) |
132 | 142 | :Temperature #(dfn/mean (:Temperature %))}) |
133 | | - (tc/order-by [:date]) |
| 143 | + (tc/order-by [:year :month :day]) |
134 | 144 | (tc/head 10)) |
135 | 145 |
|
136 | 146 | ;; Monthly averages: |
|
155 | 165 | (tc/group-by [:weekend? :hour]) |
156 | 166 | (tc/aggregate {:Demand #(dfn/mean (:Demand %))}) |
157 | 167 | (tc/order-by [:hour]) |
158 | | - (plotly/layer-line {:=x :hour |
159 | | - :=y :Demand |
| 168 | + (plotly/layer-line {:=x :hour |
| 169 | + :=y :Demand |
160 | 170 | :=color :weekend?})) |
161 | 171 |
|
162 | 172 | ;; Weekday demand shows the classic two-peak pattern (morning and evening), |
|
0 commit comments