Translating fpp3 Chapter 2 examples from R to Clojure using tablecloth, tablecloth.time, and plotje.
Reference: https://otexts.com/fpp3/graphics.html
Review figures: clj -M:notebooks -m plotje-review
(ns chapter-02-plotje
(:require [tablecloth.api :as tc]
[tech.v3.datatype.functional :as dfn]
[scicloj.plotje.api :as pj]
[tablecloth.time.api :as tct]))(defn load-fpp3
"Load one of the fpp3 datasets from CSV."
[name]
(tc/dataset (str "data/fpp3/" name ".csv") {:key-fn keyword}))(def PBS (load-fpp3 "PBS"))PBSdata/fpp3/PBS.csv [67596 9]:
| :Month | :Concession | :Type | :ATC1 | :ATC1_desc | :ATC2 | :ATC2_desc | :Scripts | :Cost |
|---|---|---|---|---|---|---|---|---|
| 1991-07-01 | Concessional | Co-payments | A | Alimentary tract and metabolism | A01 | STOMATOLOGICAL PREPARATIONS | 18228.0 | 67877.00 |
| 1991-08-01 | Concessional | Co-payments | A | Alimentary tract and metabolism | A01 | STOMATOLOGICAL PREPARATIONS | 15327.0 | 57011.00 |
| 1991-09-01 | Concessional | Co-payments | A | Alimentary tract and metabolism | A01 | STOMATOLOGICAL PREPARATIONS | 14775.0 | 55020.00 |
| 1991-10-01 | Concessional | Co-payments | A | Alimentary tract and metabolism | A01 | STOMATOLOGICAL PREPARATIONS | 15380.0 | 57222.00 |
| 1991-11-01 | Concessional | Co-payments | A | Alimentary tract and metabolism | A01 | STOMATOLOGICAL PREPARATIONS | 14371.0 | 52120.00 |
| 1991-12-01 | Concessional | Co-payments | A | Alimentary tract and metabolism | A01 | STOMATOLOGICAL PREPARATIONS | 15028.0 | 54299.00 |
| 1992-01-01 | Concessional | Co-payments | A | Alimentary tract and metabolism | A01 | STOMATOLOGICAL PREPARATIONS | 11040.0 | 39753.00 |
| 1992-02-01 | Concessional | Co-payments | A | Alimentary tract and metabolism | A01 | STOMATOLOGICAL PREPARATIONS | 15165.0 | 54405.00 |
| 1992-03-01 | Concessional | Co-payments | A | Alimentary tract and metabolism | A01 | STOMATOLOGICAL PREPARATIONS | 16898.0 | 61108.00 |
| 1992-04-01 | Concessional | Co-payments | A | Alimentary tract and metabolism | A01 | STOMATOLOGICAL PREPARATIONS | 18141.0 | 65356.00 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2007-08-01 | General | Safety net | Z | Z | Z | 250.0 | 3030.15 | |
| 2007-09-01 | General | Safety net | Z | Z | Z | 281.0 | 3822.94 | |
| 2007-10-01 | General | Safety net | Z | Z | Z | 374.0 | 4346.34 | |
| 2007-11-01 | General | Safety net | Z | Z | Z | 501.0 | 6930.19 | |
| 2007-12-01 | General | Safety net | Z | Z | Z | 655.0 | 7939.00 | |
| 2008-01-01 | General | Safety net | Z | Z | Z | 797.0 | 9604.00 | |
| 2008-02-01 | General | Safety net | Z | Z | Z | 135.0 | 1591.00 | |
| 2008-03-01 | General | Safety net | Z | Z | Z | 15.0 | 276.00 | |
| 2008-04-01 | General | Safety net | Z | Z | Z | 11.0 | 165.00 | |
| 2008-05-01 | General | Safety net | Z | Z | Z | 21.0 | 278.00 | |
| 2008-06-01 | General | Safety net | Z | Z | Z | 57.0 | 491.00 |
In R:
PBS |> filter(ATC2 == "A10") |> select(Month, Concession, Type, Cost) |> summarise(TotalC = sum(Cost)) |> mutate(Cost = TotalC / 1e6) -> a10
(def a10
(-> PBS
(tc/select-rows #(= "A10" (:ATC2 %)))
(tc/select-columns [:Month :Concession :Type :Cost])
(tc/group-by [:Month])
(tc/aggregate {:TotalC #(dfn/sum (% :Cost))})
(tc/add-column :Cost #(dfn// (% :TotalC) 1e6))))a10_unnamed [204 3]:
| :Month | :TotalC | :Cost |
|---|---|---|
| 1991-07-01 | 3.52659100E+06 | 3.52659100 |
| 1991-08-01 | 3.18089100E+06 | 3.18089100 |
| 1991-09-01 | 3.25222100E+06 | 3.25222100 |
| 1991-10-01 | 3.61100300E+06 | 3.61100300 |
| 1991-11-01 | 3.56586900E+06 | 3.56586900 |
| 1991-12-01 | 4.30637100E+06 | 4.30637100 |
| 1992-01-01 | 5.08833500E+06 | 5.08833500 |
| 1992-02-01 | 2.81452000E+06 | 2.81452000 |
| 1992-03-01 | 2.98581100E+06 | 2.98581100 |
| 1992-04-01 | 3.20478000E+06 | 3.20478000 |
| ... | ... | ... |
| 2007-08-01 | 2.39302035E+07 | 23.93020353 |
| 2007-09-01 | 2.29303569E+07 | 22.93035694 |
| 2007-10-01 | 2.32633399E+07 | 23.26333992 |
| 2007-11-01 | 2.52500302E+07 | 25.25003022 |
| 2007-12-01 | 2.58060900E+07 | 25.80609000 |
| 2008-01-01 | 2.96653560E+07 | 29.66535600 |
| 2008-02-01 | 2.16542850E+07 | 21.65428500 |
| 2008-03-01 | 1.82649450E+07 | 18.26494500 |
| 2008-04-01 | 2.31076770E+07 | 23.10767700 |
| 2008-05-01 | 2.29125100E+07 | 22.91251000 |
| 2008-06-01 | 1.94317400E+07 | 19.43174000 |
(def ansett (load-fpp3 "ansett"))ansettdata/fpp3/ansett.csv [7407 4]:
| :Week | :Airports | :Class | :Passengers |
|---|---|---|---|
| 1989-07-10 | ADL-PER | Business | 193.0 |
| 1989-07-17 | ADL-PER | Business | 254.0 |
| 1989-07-24 | ADL-PER | Business | 185.0 |
| 1989-07-31 | ADL-PER | Business | 254.0 |
| 1989-08-07 | ADL-PER | Business | 191.0 |
| 1989-08-14 | ADL-PER | Business | 136.0 |
| 1989-08-21 | ADL-PER | Business | 0.0 |
| 1989-08-28 | ADL-PER | Business | 0.0 |
| 1989-09-04 | ADL-PER | Business | 0.0 |
| 1989-09-11 | ADL-PER | Business | 0.0 |
| ... | ... | ... | ... |
| 1992-09-07 | SYD-PER | First | 176.0 |
| 1992-09-14 | SYD-PER | First | 191.0 |
| 1992-09-21 | SYD-PER | First | 204.0 |
| 1992-09-28 | SYD-PER | First | 183.0 |
| 1992-10-05 | SYD-PER | First | 220.0 |
| 1992-10-12 | SYD-PER | First | 234.0 |
| 1992-10-19 | SYD-PER | First | 203.0 |
| 1992-10-26 | SYD-PER | First | 137.0 |
| 1992-11-02 | SYD-PER | First | 161.0 |
| 1992-11-09 | SYD-PER | First | 155.0 |
| 1992-11-16 | SYD-PER | First | 188.0 |
(def aus-production (load-fpp3 "aus_production"))aus-productiondata/fpp3/aus_production.csv [218 7]:
| :Quarter | :Beer | :Tobacco | :Bricks | :Cement | :Electricity | :Gas |
|---|---|---|---|---|---|---|
| 1956-01-01 | 284.0 | 5225.0 | 189.0 | 465.0 | 3923.0 | 5.0 |
| 1956-04-01 | 213.0 | 5178.0 | 204.0 | 532.0 | 4436.0 | 6.0 |
| 1956-07-01 | 227.0 | 5297.0 | 208.0 | 561.0 | 4806.0 | 7.0 |
| 1956-10-01 | 308.0 | 5681.0 | 197.0 | 570.0 | 4418.0 | 6.0 |
| 1957-01-01 | 262.0 | 5577.0 | 187.0 | 529.0 | 4339.0 | 5.0 |
| 1957-04-01 | 228.0 | 5651.0 | 214.0 | 604.0 | 4811.0 | 7.0 |
| 1957-07-01 | 236.0 | 5317.0 | 227.0 | 603.0 | 5259.0 | 7.0 |
| 1957-10-01 | 320.0 | 6152.0 | 222.0 | 582.0 | 4735.0 | 6.0 |
| 1958-01-01 | 272.0 | 5758.0 | 199.0 | 554.0 | 4608.0 | 5.0 |
| 1958-04-01 | 233.0 | 5641.0 | 229.0 | 620.0 | 5196.0 | 7.0 |
| ... | ... | ... | ... | ... | ... | ... |
| 2007-10-01 | 473.0 | 2562.0 | 56411.0 | 205.0 | ||
| 2008-01-01 | 420.0 | 2183.0 | 59118.0 | 194.0 | ||
| 2008-04-01 | 390.0 | 2558.0 | 56660.0 | 229.0 | ||
| 2008-07-01 | 410.0 | 2612.0 | 64067.0 | 249.0 | ||
| 2008-10-01 | 488.0 | 2373.0 | 59045.0 | 203.0 | ||
| 2009-01-01 | 415.0 | 1963.0 | 58368.0 | 196.0 | ||
| 2009-04-01 | 398.0 | 2160.0 | 57471.0 | 238.0 | ||
| 2009-07-01 | 419.0 | 2325.0 | 58394.0 | 252.0 | ||
| 2009-10-01 | 488.0 | 2273.0 | 57336.0 | 210.0 | ||
| 2010-01-01 | 414.0 | 1904.0 | 58309.0 | 205.0 | ||
| 2010-04-01 | 374.0 | 2401.0 | 58041.0 | 236.0 |
Timestamps are stored in UTC; convert them to Melbourne time so years and seasons follow the local clock.
(def vic-elec
(-> (load-fpp3 "vic_elec")
(tc/convert-types :Time [:local-date-time "yyyy-MM-dd HH:mm:ss"])
(tct/replace-time-zone :Time "UTC")
(tct/convert-time-zone :Time "Australia/Melbourne")))vic-elecdata/fpp3/vic_elec.csv [52608 5]:
| :Time | :Demand | :Temperature | :Date | :Holiday |
|---|---|---|---|---|
| 2012-01-01T00:00+11:00[Australia/Melbourne] | 4382.825174 | 21.40 | 2012-01-01 | True |
| 2012-01-01T00:30+11:00[Australia/Melbourne] | 4263.365526 | 21.05 | 2012-01-01 | True |
| 2012-01-01T01:00+11:00[Australia/Melbourne] | 4048.966046 | 20.70 | 2012-01-01 | True |
| 2012-01-01T01:30+11:00[Australia/Melbourne] | 3877.563330 | 20.55 | 2012-01-01 | True |
| 2012-01-01T02:00+11:00[Australia/Melbourne] | 4036.229746 | 20.40 | 2012-01-01 | True |
| 2012-01-01T02:30+11:00[Australia/Melbourne] | 3865.597244 | 20.25 | 2012-01-01 | True |
| 2012-01-01T03:00+11:00[Australia/Melbourne] | 3694.097664 | 20.10 | 2012-01-01 | True |
| 2012-01-01T03:30+11:00[Australia/Melbourne] | 3561.623686 | 19.60 | 2012-01-01 | True |
| 2012-01-01T04:00+11:00[Australia/Melbourne] | 3433.035352 | 19.10 | 2012-01-01 | True |
| 2012-01-01T04:30+11:00[Australia/Melbourne] | 3359.468000 | 18.95 | 2012-01-01 | True |
| ... | ... | ... | ... | ... |
| 2014-12-31T18:30+11:00[Australia/Melbourne] | 4244.465530 | 23.40 | 2014-12-31 | False |
| 2014-12-31T19:00+11:00[Australia/Melbourne] | 4125.988252 | 22.30 | 2014-12-31 | False |
| 2014-12-31T19:30+11:00[Australia/Melbourne] | 4013.262848 | 20.90 | 2014-12-31 | False |
| 2014-12-31T20:00+11:00[Australia/Melbourne] | 3924.593434 | 20.30 | 2014-12-31 | False |
| 2014-12-31T20:30+11:00[Australia/Melbourne] | 3893.867974 | 20.30 | 2014-12-31 | False |
| 2014-12-31T21:00+11:00[Australia/Melbourne] | 3927.753088 | 20.30 | 2014-12-31 | False |
| 2014-12-31T21:30+11:00[Australia/Melbourne] | 3873.448714 | 19.00 | 2014-12-31 | False |
| 2014-12-31T22:00+11:00[Australia/Melbourne] | 3791.637322 | 18.50 | 2014-12-31 | False |
| 2014-12-31T22:30+11:00[Australia/Melbourne] | 3724.835666 | 17.70 | 2014-12-31 | False |
| 2014-12-31T23:00+11:00[Australia/Melbourne] | 3761.886854 | 17.30 | 2014-12-31 | False |
| 2014-12-31T23:30+11:00[Australia/Melbourne] | 3809.414586 | 17.10 | 2014-12-31 | False |
(def tourism (load-fpp3 "tourism"))tourismdata/fpp3/tourism.csv [24320 5]:
| :Quarter | :Region | :State | :Purpose | :Trips |
|---|---|---|---|---|
| 1998-01-01 | Adelaide | South Australia | Business | 135.0776903 |
| 1998-04-01 | Adelaide | South Australia | Business | 109.9873160 |
| 1998-07-01 | Adelaide | South Australia | Business | 166.0346866 |
| 1998-10-01 | Adelaide | South Australia | Business | 127.1604643 |
| 1999-01-01 | Adelaide | South Australia | Business | 137.4485333 |
| 1999-04-01 | Adelaide | South Australia | Business | 199.9125861 |
| 1999-07-01 | Adelaide | South Australia | Business | 169.3550898 |
| 1999-10-01 | Adelaide | South Australia | Business | 134.3579372 |
| 2000-01-01 | Adelaide | South Australia | Business | 154.0343980 |
| 2000-04-01 | Adelaide | South Australia | Business | 168.7763637 |
| ... | ... | ... | ... | ... |
| 2015-04-01 | Yorke Peninsula | South Australia | Visiting | 35.5787294 |
| 2015-07-01 | Yorke Peninsula | South Australia | Visiting | 8.0412485 |
| 2015-10-01 | Yorke Peninsula | South Australia | Visiting | 24.1803395 |
| 2016-01-01 | Yorke Peninsula | South Australia | Visiting | 40.5119543 |
| 2016-04-01 | Yorke Peninsula | South Australia | Visiting | 26.8346812 |
| 2016-07-01 | Yorke Peninsula | South Australia | Visiting | 22.7588087 |
| 2016-10-01 | Yorke Peninsula | South Australia | Visiting | 33.6721508 |
| 2017-01-01 | Yorke Peninsula | South Australia | Visiting | 46.2230139 |
| 2017-04-01 | Yorke Peninsula | South Australia | Visiting | 50.5828371 |
| 2017-07-01 | Yorke Peninsula | South Australia | Visiting | 27.7667276 |
| 2017-10-01 | Yorke Peninsula | South Australia | Visiting | 46.2815777 |
R: autoplot(melsyd_economy, Passengers)
(def melsyd-economy
(-> ansett
(tc/select-rows #(and (= "MEL-SYD" (:Airports %))
(= "Economy" (:Class %))))
(tc/add-column :Passengers-000s #(dfn// (% :Passengers) 1000))))(def melsyd-economy-plot
(-> melsyd-economy
(pj/lay-line :Week :Passengers-000s)
(pj/options {:title "Ansett airlines economy class: Melbourne-Sydney"})))melsyd-economy-plotNotable features visible in the plot:
R: autoplot(a10, Cost)
(def a10-plot
(-> a10
(pj/lay-line :Month :Cost)
(pj/options {:title "Australian antidiabetic drug sales"
:y-label "$ (millions)"})))a10-plotClear increasing trend with strong seasonality that grows proportionally. The January spike each year is from stockpiling before year-end subsidies.
Three fundamental components:
(def recent-beer
(-> aus-production
(tct/add-time-columns :Quarter {:year :Year})
(tc/select-rows #(>= (:Year %) 2000))
(tc/select-columns [:Quarter :Beer])))(def recent-beer-plot
(-> recent-beer
(pj/lay-line :Quarter :Beer)
(pj/options {:title "Australian quarterly beer production"})))recent-beer-plot(def gafa (load-fpp3 "gafa_stock"))(def google-2015
(-> gafa
(tct/add-time-columns :Date {:year :Year})
(tc/select-rows #(and (= "GOOG" (:Symbol %))
(= (:Year %) 2015)))))Daily closing price
(def google-2015-close-plot
(-> google-2015
(pj/lay-line :Date :Close)
(pj/options {:title "Google daily closing stock price (2015)"})))google-2015-close-plotDaily change in closing price; the first day has no previous close.
(def google-2015-change
(-> google-2015
(tct/add-lag :Close 1 :Close-lag1)
(tc/drop-missing [:Close-lag1])
(tc/add-column :Change #(dfn/- (% :Close) (% :Close-lag1)))
(tc/select-columns [:Date :Change])))(def google-2015-change-plot
(-> google-2015-change
(pj/lay-line :Date :Change)
(pj/options {:title "Google daily change in closing stock price (2015)"})))google-2015-change-plotfpp3 colours each season by year on a continuous scale. Plotje cannot yet colour lines by a numeric column, so years are categories, each given a shade from dark (earliest) to light (latest) blue.
(defn year-colors
"Map each year string to a shade of blue, darkest first."
[years]
(let [ys (sort (distinct years))
n (max 1 (dec (count ys)))
lerp (fn [a b t] (int (+ a (* t (- b a)))))]
(into {}
(map-indexed (fn [i y]
(let [t (/ i n)]
[y (format "#%02x%02x%02x"
(lerp 0x13 0x56 t)
(lerp 0x2b 0xb1 t)
(lerp 0x43 0xf7 t))]))
ys))))(def month-names ["Jan" "Feb" "Mar" "Apr" "May" "Jun"
"Jul" "Aug" "Sep" "Oct" "Nov" "Dec"])R: gg_season(a10, Cost, labels = "both")
(def a10-seasonal
(-> a10
(tct/add-time-columns :Month {:year-string :Year :month :MonthNum})
(tc/order-by [:Year :MonthNum])))(def a10-seasonal-plot
(-> a10-seasonal
(pj/lay-line :MonthNum :Cost {:color :Year})
(pj/scale :x {:breaks (range 1 13) :tick-labels month-names})
(pj/options {:title "Seasonal plot: Antidiabetic drug sales"
:x-label "Month"
:y-label "$ (millions)"
:color-label "Year"
:color-values (year-colors (a10-seasonal :Year))})))a10-seasonal-plotR: gg_season(Demand, period = "day" | "week" | "year") Each period gets its own x position and its own line grouping.
(def vic-elec-seasonal
(-> vic-elec
(tct/add-time-columns :Time {:year-string :Year
:date-string :Day
:day-of-week :DayOfWeek
:day-of-year :DayOfYear
:hour-fractional :Hour
:weekly-phase :WeeklyPhase})
(tc/add-column :DayOfWeekFrac #(dfn/* (% :WeeklyPhase) 7))
(tc/add-column :DayOfYearFrac #(dfn/+ (dfn/- (% :DayOfYear) 1) (dfn// (% :Hour) 24)))
(tc/add-column :WeekStart
#(map (fn [day dow]
(str (.minusDays (java.time.LocalDate/parse day) (dec dow))))
(% :Day) (% :DayOfWeek)))
(tc/order-by [:Time])))(def vic-elec-year-colors (year-colors (vic-elec-seasonal :Year)))Daily: one line per day.
(def vic-elec-daily-plot
(-> vic-elec-seasonal
(pj/lay-line :Hour :Demand {:color :Year :group :Day :size 0.3 :alpha 0.5})
(pj/scale :x {:breaks (range 0 25 3)})
(pj/options {:title "Electricity demand: Victoria (daily pattern)"
:x-label "Hour of day"
:y-label "MWh"
:color-label "Year"
:color-values vic-elec-year-colors
:width 800})))vic-elec-daily-plotWeekly: one line per Monday-to-Sunday week.
(def vic-elec-weekly-plot
(-> vic-elec-seasonal
(pj/lay-line :DayOfWeekFrac :Demand {:color :Year :group :WeekStart
:size 0.3 :alpha 0.5})
(pj/scale :x {:breaks (range 7)
:tick-labels ["Mon" "Tue" "Wed" "Thu" "Fri" "Sat" "Sun"]})
(pj/options {:title "Electricity demand: Victoria (weekly pattern)"
:x-label "Day of week"
:y-label "MWh"
:color-label "Year"
:color-values vic-elec-year-colors
:width 800})))vic-elec-weekly-plotYearly: one line per year, ticked at the first day of each month.
(def vic-elec-yearly-plot
(-> vic-elec-seasonal
(pj/lay-line :DayOfYearFrac :Demand {:color :Year :size 0.3})
(pj/scale :x {:breaks (map #(dec (.getDayOfYear (java.time.LocalDate/of 2013 (int %) 1)))
(range 1 13))
:tick-labels month-names})
(pj/options {:title "Electricity demand: Victoria (yearly pattern)"
:x-label "Day of year"
:y-label "MWh"
:color-label "Year"
:color-values vic-elec-year-colors
:width 800})))vic-elec-yearly-plotR: gg_subseries(a10, Cost) — for each month, show values across years with the mean as a horizontal line.
Each row carries its month's mean in :MeanCost, so the mean draws as a flat line in every panel. Facets follow the order rows first appear in, so rows are sorted by month before faceting.
(def a10-subseries
(-> a10
(tct/add-time-columns :Month {:year :Year :month :MonthNum})
(tc/order-by [:MonthNum :Year])
(tc/group-by [:MonthNum])
(tc/add-column :MeanCost #(repeat (tc/row-count %) (dfn/mean (% :Cost))))
(tc/ungroup)
(tc/add-column :MonthName #(map (comp month-names dec) (% :MonthNum)))))(def a10-subseries-plot
(-> a10-subseries
pj/overlay
(pj/lay-line :Year :Cost)
(pj/lay-point :Year :Cost)
(pj/lay-line :Year :MeanCost {:color "#1f77b4"})
(pj/facet :MonthName)
(pj/options {:title "Subseries: Australian antidiabetic drug sales"
:y-label "$ (millions)"
:width 1200
:height 350})))a10-subseries-plotThe means show January's stockpiling peak, a February drop, then a slow climb to December. Every month trends upward across the years.
R: tourism |> filter(Purpose == "Holiday") |> group_by(State) |> summarise(Trips = sum(Trips))
(def holidays
(-> tourism
(tc/select-rows #(= "Holiday" (:Purpose %)))
(tc/group-by [:Quarter :State])
(tc/aggregate {:Trips #(dfn/sum (% :Trips))})
(tct/add-time-columns :Quarter {:year-string :Year :quarter :QuarterNum})
(tc/order-by [:State :Quarter])))R: autoplot(holidays, Trips)
(def holidays-plot
(-> holidays
(pj/lay-line :Quarter :Trips {:color :State})
(pj/options {:title "Australian domestic holidays"
:y-label "Overnight trips ('000)"
:width 800})))holidays-plotR: gg_season(holidays, Trips) — one panel per state, each with its own y scale, one line per year.
(def holidays-seasonal-plot
(-> holidays
(pj/lay-line :QuarterNum :Trips {:color :Year})
(pj/facet :State :row)
(pj/scale :x {:breaks (range 1 5) :tick-labels ["Q1" "Q2" "Q3" "Q4"]})
(pj/options {:title "Australian domestic tourism: Holiday trips"
:x-label "Quarter"
:y-label "Overnight trips ('000)"
:color-label "Year"
:color-values (year-colors (holidays :Year))
:scales :free-y
:line-width 1
:width 600
:height 1100})))holidays-seasonal-plotSouthern states (Victoria, Tasmania) peak in summer (Q1); northern ones (Queensland, Northern Territory) in winter and spring (Q3).
(def vic-elec-2014
(-> vic-elec
(tct/add-time-columns :Time {:year :Year})
(tc/select-rows #(= 2014 (:Year %)))
(tc/add-column :Demand-GW #(dfn// (% :Demand) 1000))))R: autoplot(Demand)
(def vic-elec-demand-plot
(-> vic-elec-2014
(pj/lay-line :Time :Demand-GW {:size 0.5})
(pj/options {:title "Half-hourly electricity demand: Victoria"
:y-label "GW"})))vic-elec-demand-plotR: autoplot(Temperature)
(def vic-elec-temperature-plot
(-> vic-elec-2014
(pj/lay-line :Time :Temperature {:size 0.5})
(pj/options {:title "Half-hourly temperatures: Melbourne, Australia"
:y-label "Degrees Celsius"})))vic-elec-temperature-plotR: ggplot(aes(x = Temperature, y = Demand)) + geom_point()
(def demand-vs-temperature-plot
(-> vic-elec-2014
(pj/lay-point :Temperature :Demand-GW {:size 1 :alpha 0.5})
(pj/options {:title "Electricity demand vs temperature: Victoria, 2014"
:x-label "Temperature (degrees Celsius)"
:y-label "Electricity demand (GW)"})))demand-vs-temperature-plotDemand is high for both cold (heating) and hot (air conditioning) days. A correlation coefficient misses this non-linear shape; plot first.
R: pivot_wider(values_from = Trips, names_from = State) |> GGally::ggpairs(columns = 2:9)
(def visitors-by-state
(-> tourism
(tc/group-by [:Quarter :State])
(tc/aggregate {:Trips #(dfn/sum (% :Trips))})
(tc/pivot->wider :State :Trips)))visitors-by-state_unnamed [80 9]:
| :Quarter | South Australia | Northern Territory | Western Australia | Victoria | New South Wales | Queensland | ACT | Tasmania |
|---|---|---|---|---|---|---|---|---|
| 1998-01-01 | 1735.4384181 | 181.4488234 | 1641.0894945 | 6010.4244905 | 8039.7947954 | 4041.3701591 | 551.0019215 | 981.6291663 |
| 1998-04-01 | 1394.6383194 | 313.9361515 | 1576.3265337 | 4795.2467552 | 7166.0138053 | 3967.9046526 | 416.0256229 | 693.2882267 |
| 1998-07-01 | 1213.3307229 | 528.4368592 | 1588.2936922 | 4316.8451697 | 6747.9357896 | 4593.8939910 | 436.0290111 | 401.8752750 |
| 1998-10-01 | 1452.5699692 | 247.7028173 | 1839.7169904 | 4674.8291177 | 7282.0823712 | 4202.8291407 | 449.7984449 | 680.6010392 |
| 1999-01-01 | 1541.1817910 | 184.8895923 | 1835.6875729 | 5304.3341954 | 7584.7768389 | 4332.4908503 | 378.5728168 | 925.4197220 |
| 1999-04-01 | 1636.1154606 | 366.0927858 | 1836.9642903 | 4561.7109009 | 7054.0387051 | 4824.4804518 | 558.1781421 | 620.7925480 |
| 1999-07-01 | 1282.9490168 | 501.4312841 | 1725.3748681 | 3783.6010393 | 6723.6771461 | 5018.0345042 | 448.9011959 | 430.2234538 |
| 1999-10-01 | 1386.9430724 | 248.4302996 | 1518.9426972 | 4201.4224779 | 7135.7669454 | 4349.8358766 | 594.8254416 | 591.7588297 |
| 2000-01-01 | 1832.8466955 | 206.0532200 | 1635.5250181 | 5566.8572876 | 7295.9866387 | 4413.2262339 | 599.6685405 | 789.1311444 |
| 2000-04-01 | 1415.4842932 | 359.7619246 | 1808.3286160 | 4501.9042822 | 6445.2201677 | 4344.1592770 | 557.1350565 | 509.0698648 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2015-04-01 | 1561.2069129 | 533.0254161 | 2394.3740364 | 5284.4708775 | 7375.2085323 | 5555.8301970 | 516.8703428 | 577.9280518 |
| 2015-07-01 | 1383.9080928 | 682.5518237 | 2467.0642463 | 4981.1688294 | 6961.2502033 | 5866.0704509 | 688.2031884 | 455.5288199 |
| 2015-10-01 | 1700.3825231 | 423.2025164 | 2743.4490648 | 5550.8237034 | 7760.0190221 | 5532.2106436 | 597.2455694 | 832.8281787 |
| 2016-01-01 | 1871.4572503 | 352.0984958 | 2871.1718747 | 6599.7004830 | 8287.8720804 | 5042.1537503 | 625.1416344 | 1011.0421206 |
| 2016-04-01 | 1660.1266358 | 469.1365356 | 2469.3942809 | 5335.2297369 | 7660.5796206 | 5446.5536505 | 592.6084987 | 651.3987982 |
| 2016-07-01 | 1534.2342547 | 713.8207499 | 2317.0445437 | 5221.8805097 | 7326.3046707 | 5939.3346446 | 572.4370928 | 566.2636651 |
| 2016-10-01 | 1635.4677141 | 340.6959274 | 2656.3307006 | 6113.0164129 | 7995.5021920 | 6106.3838529 | 667.2141410 | 832.9900323 |
| 2017-01-01 | 1815.4121833 | 298.1660264 | 2570.9116892 | 7269.5270136 | 8320.7034623 | 5451.9871280 | 634.3687469 | 1135.3127709 |
| 2017-04-01 | 1660.1320376 | 621.4413922 | 2438.4879387 | 5901.3865473 | 8285.0262795 | 5638.4735354 | 748.2904309 | 820.3685463 |
| 2017-07-01 | 1514.7861308 | 597.6583969 | 2493.9549995 | 5817.9715437 | 8298.2574173 | 6533.8369322 | 631.7599043 | 618.0893828 |
| 2017-10-01 | 1869.1069854 | 346.0619384 | 2635.7542961 | 6865.3988511 | 8542.4906073 | 5813.9036668 | 720.3293701 | 800.5084986 |
(def states (sort (remove #{:Quarter} (tc/column-names visitors-by-state))))pj/cross pairs every state with every other; the diagonal shows each state's distribution.
(def tourism-splom-plot
(-> visitors-by-state
(pj/pose (pj/cross states states) {:size 1.5})
(pj/options {:width 1250
:height 1000})))tourism-splom-plotR: recent_production |> gg_lag(Beer, geom = "point") Each panel plots beer production y_t against y_{t-k}, coloured by quarter.
(def lags (range 1 10))(def beer-lags
(-> recent-beer
(tct/add-time-columns :Quarter {:quarter :Q})
(tc/add-column :Quarter-of-year #(map (partial str "Q") (% :Q)))))(defn lag-panel
[k]
(let [lagged (-> beer-lags
(tct/add-lag :Beer k :Beer-lagged)
(tc/drop-missing [:Beer-lagged])
(tc/order-by [:Q]))
diagonal (tc/dataset {:from [(dfn/reduce-min (recent-beer :Beer))]
:to [(dfn/reduce-max (recent-beer :Beer))]})]
(-> lagged
(pj/lay-point :Beer-lagged :Beer {:color :Quarter-of-year})
(pj/lay-segment :from :from {:data diagonal
:x-end :to
:y-end :to
:stroke-dash :dashed
:alpha 0.5
:overlay true})
(pj/options {:title (str "lag " k)
:x-label "lag(Beer, k)"
:color-label "Quarter"}))))(def beer-lag-plot
(pj/arrange (map lag-panel lags)
{:cols 3
:share-scales #{:x :y}
:width 900
:height 900}))beer-lag-plotLags 4 and 8 sit on the diagonal: each quarter matches the same quarter a year earlier. Lags 2 and 6 are negative: Q4 peaks pair with Q2 troughs.
Figures exported by plotje-review, keyed by output file name.
(def figures
{"a10" a10-plot
"melsyd-economy" melsyd-economy-plot
"recent-beer" recent-beer-plot
"google-2015-close" google-2015-close-plot
"google-2015-change" google-2015-change-plot
"a10-seasonal" a10-seasonal-plot
"vic-elec-daily" vic-elec-daily-plot
"vic-elec-weekly" vic-elec-weekly-plot
"vic-elec-yearly" vic-elec-yearly-plot
"a10-subseries" a10-subseries-plot
"holidays" holidays-plot
"holidays-seasonal" holidays-seasonal-plot
"vic-elec-demand-2014" vic-elec-demand-plot
"vic-elec-temperature-2014" vic-elec-temperature-plot
"demand-vs-temperature" demand-vs-temperature-plot
"tourism-splom" tourism-splom-plot
"beer-lag" beer-lag-plot})source: notebooks/chapter_02_plotje.clj