German Electricity Data :electric_plug:¶

  • Data Source: SMARD Web Portal
  • Task: forecasting (using the past to predict the future)
  • Language: R

First steps:¶

  • load the data (with appropriate column types) :heavy_check_mark:
  • split the data into train/val/test sets :heavy_check_mark:
  • plot the time series (at different temporal resolution) :heavy_check_mark:
  • calculate the mean production per month :heavy_check_mark:
  • is there a seasonal pattern (what kinds of seasonalities)
  • make a prediction for the validation set
  • evaluate the quality of the prediction
In [7]:
library(tidyverse)
In [8]:
theme_set(theme_light())
In [9]:
set.seed(42)
"Simon Maik Max Dharu Robin" %>%  str_split(" ") %>% unlist %>% sample %>% str_c(collapse=" → ")
Out[9]:
'Simon → Robin → Dharu → Max → Maik'

1. Data loading¶

  • load the hourly data from the file Realisierte_Erzeugung_201501010000_202305301300_Stunde.csv as a table into R :heavy_check_mark:
  • make sure, that data is interpreted and typed correctly :heavy_check_mark:
  • clean header names :heavy_check_mark:
  • create column Time containing the combined info from Datum and Anfang
In [10]:
data <- read_csv2(
    "../data_dojo_22/Realisierte_Erzeugung_201501010000_202305301300_Stunde.csv",
    col_types=cols(`Datum` = col_date("%d.%m.%Y")),
    na="-"
)
ℹ Using "','" as decimal and "'.'" as grouping mark. Use `read_delim()` for more control.

In [11]:
colnames(data) <- colnames(data) %>% str_remove(" \\[.*") %>% str_replace(" ","_")

2nd session¶

  • Create Time column
  • Split into training/validation/test set
  • Plot the training set with hourly resolution
  • Aggregate by day/month
  • Plot aggregated data
Bonus task
  • did you observe something peculiar with dates and times?
  • look at the hourly data of 2017-10-29 for an example
  • what happened there?
  • are there more days with a similar "problem"?
  • is this a problem?
  • how can we solve this?
In [12]:
data <- data %>%
    mutate(Time=Datum+hours(hour(Anfang)))
In [13]:
data
Out[13]:
A tibble: 73716 × 16
DatumAnfangEndeBiomasseWasserkraftWind_OffshoreWind_OnshorePhotovoltaikSonstige_ErneuerbareKernenergieBraunkohleSteinkohleErdgasPumpspeicherSonstige_KonventionelleTime
<date><time><time><dbl><dbl><dbl><dbl><dbl><dbl><dbl><dbl><dbl><dbl><dbl><dbl><dttm>
2015-01-0100:00:0001:00:004024.251158.25516.50 8128.00 0.00133.0010710.5015687.253219.751226.251525.754909.252015-01-01 00:00:00
2015-01-0101:00:0002:00:003982.751188.00516.25 8297.50 0.00122.5011086.2515321.752351.25 870.751079.254932.752015-01-01 01:00:00
2015-01-0102:00:0003:00:004019.501139.25514.00 8540.00 0.00 93.0011026.2514817.502227.00 809.50 787.005041.752015-01-01 02:00:00
2015-01-0103:00:0004:00:004040.751122.50517.75 8552.00 0.00 86.5011027.7514075.002339.75 821.00 287.755084.002015-01-01 03:00:00
2015-01-0104:00:0005:00:004037.751112.00519.75 8643.50 0.00 86.5010962.2514115.002461.50 831.25 346.755070.752015-01-01 04:00:00
2015-01-0105:00:0006:00:004028.251107.75520.00 8711.75 0.00 86.7510696.0013474.252217.75 851.00 765.505096.752015-01-01 05:00:00
2015-01-0106:00:0007:00:004013.251111.75521.50 9167.25 0.00 87.0010299.5012403.752373.25 868.25 414.505153.002015-01-01 06:00:00
2015-01-0107:00:0008:00:004012.751113.75520.25 9811.00 0.00 87.0010035.2512062.502491.00 876.00 582.505161.002015-01-01 07:00:00
2015-01-0108:00:0009:00:003999.751107.50525.25 9683.00 53.00 87.0010245.7512405.002530.25 888.25 750.505393.502015-01-01 08:00:00
2015-01-0109:00:0010:00:004016.251121.00527.00 9501.75 773.25 85.7510060.2512798.752386.25 891.50 387.005884.002015-01-01 09:00:00
2015-01-0110:00:0011:00:004007.751122.00525.0010025.002116.75 82.0010082.2512728.502557.00 888.25 176.256064.002015-01-01 10:00:00
2015-01-0111:00:0012:00:004011.751146.25527.2510862.503364.25 82.00 9949.0012451.002657.75 876.50 884.505914.752015-01-01 11:00:00
2015-01-0112:00:0013:00:004014.001139.75527.7511575.254198.25 82.0010119.0012464.502937.75 874.25 705.005778.252015-01-01 12:00:00
2015-01-0113:00:0014:00:004005.501128.00527.7511977.253500.50 84.5010453.5012417.752810.25 883.50 967.255808.752015-01-01 13:00:00
2015-01-0114:00:0015:00:004024.251154.75524.7511396.002278.75 87.0010828.2512621.502664.00 890.251176.255842.502015-01-01 14:00:00
2015-01-0115:00:0016:00:004028.751160.00524.5011326.50 745.50 86.0011069.7513387.252485.25 969.251663.006075.252015-01-01 15:00:00
2015-01-0116:00:0017:00:004030.751145.75524.5013058.00 50.00 82.0011006.5014679.002668.751085.251227.005946.002015-01-01 16:00:00
2015-01-0117:00:0018:00:004029.251171.50524.5014911.50 0.00 82.2511057.5014964.252808.751193.751597.755464.502015-01-01 17:00:00
2015-01-0118:00:0019:00:004027.501168.50524.0016344.00 0.00 86.0010930.2514286.002690.251135.501320.005604.002015-01-01 18:00:00
2015-01-0119:00:0020:00:004002.751157.75523.5017484.50 0.00 87.7510861.7513498.002490.751123.751535.505866.252015-01-01 19:00:00
2015-01-0120:00:0021:00:003991.501168.25522.2518659.00 0.00 88.0010343.0012366.002440.001209.251162.755861.252015-01-01 20:00:00
2015-01-0121:00:0022:00:003990.251186.50521.0019831.50 0.00 88.00 9840.0011284.752409.001205.75 838.756090.752015-01-01 21:00:00
2015-01-0122:00:0023:00:004000.001170.25519.5020716.00 0.00 88.00 9749.0010428.502298.751324.252066.756084.752015-01-01 22:00:00
2015-01-0123:00:0000:00:004002.001162.00494.0021589.00 0.00 88.00 9045.75 9861.252209.251212.751436.255989.252015-01-01 23:00:00
2015-01-0200:00:0001:00:003999.751122.00305.0022166.75 0.00 88.00 8164.75 9035.502225.501172.001301.005978.002015-01-02 00:00:00
2015-01-0201:00:0002:00:004003.251129.25276.5023158.00 0.00 87.75 7147.75 9013.502188.751127.75 893.506370.752015-01-02 01:00:00
2015-01-0202:00:0003:00:003997.251124.25282.0023966.00 0.00 87.75 6675.75 9018.501974.501123.25 608.505873.752015-01-02 02:00:00
2015-01-0203:00:0004:00:004000.001133.25324.7524708.75 0.00 87.75 6466.75 8765.001907.001120.25 203.505858.002015-01-02 03:00:00
2015-01-0204:00:0005:00:003992.001122.25335.0025386.00 0.00 88.00 6304.00 8398.252098.751129.75 712.506012.752015-01-02 04:00:00
2015-01-0205:00:0006:00:003981.501100.75388.2525783.75 0.00 88.00 6760.00 8593.002406.001157.50 729.256221.252015-01-02 05:00:00
⋮⋮⋮⋮⋮⋮⋮⋮⋮⋮⋮⋮⋮⋮⋮⋮
2023-05-2907:00:0008:00:004489.002074.502402.00 6005.75 9430.50117.0003455.751583.252201.251292.751444.752023-05-29 07:00:00
2023-05-2908:00:0009:00:004523.252068.752560.00 4323.7517827.00117.0003462.501812.002127.00 935.001448.002023-05-29 08:00:00
2023-05-2909:00:0010:00:004571.752071.502365.50 3468.7525662.25117.0003450.251726.002052.25 476.001449.752023-05-29 09:00:00
2023-05-2910:00:0011:00:004579.002072.001576.25 3647.0031928.50117.0003450.751691.752025.00 215.751448.002023-05-29 10:00:00
2023-05-2911:00:0012:00:004594.752032.251447.50 3519.5035927.00117.0003424.251684.252041.00 225.001445.752023-05-29 11:00:00
2023-05-2912:00:0013:00:004584.251643.001128.25 3267.2537681.50117.0003176.251464.752029.00 152.001433.752023-05-29 12:00:00
2023-05-2913:00:0014:00:004545.501598.75 855.00 3471.7537628.50117.0003178.001290.502043.75 161.251439.252023-05-29 13:00:00
2023-05-2914:00:0015:00:004509.751574.50 697.00 3401.0035503.25117.0003166.251273.002062.25 19.751419.002023-05-29 14:00:00
2023-05-2915:00:0016:00:004482.501518.251243.25 4111.7531892.50117.0003169.501266.502077.50 2.501386.752023-05-29 15:00:00
2023-05-2916:00:0017:00:004458.001648.502406.50 7099.5027421.75117.2503174.501282.502055.00 11.251408.252023-05-29 16:00:00
2023-05-2917:00:0018:00:004449.502067.252649.50 9514.0020541.50125.7503390.751326.002118.50 109.751421.502023-05-29 17:00:00
2023-05-2918:00:0019:00:004465.002099.004183.5012215.5012323.25126.0003441.501375.002348.75 360.001405.752023-05-29 18:00:00
2023-05-2919:00:0020:00:004508.252099.504259.7513248.00 5363.50134.2503643.251350.253261.25 815.001384.252023-05-29 19:00:00
2023-05-2920:00:0021:00:004562.002144.004221.0013197.00 1635.00133.2503861.001323.003647.751620.501174.002023-05-29 20:00:00
2023-05-2921:00:0022:00:004600.502119.504300.2514307.75 79.00132.7504030.001422.503970.751577.001170.502023-05-29 21:00:00
2023-05-2922:00:0023:00:004634.252117.504509.2514627.50 0.00123.0003946.751466.003681.751807.751154.502023-05-29 22:00:00
2023-05-2923:00:0000:00:004651.252066.504647.2514237.50 0.00122.0003713.001368.253729.75 900.251154.252023-05-29 23:00:00
2023-05-3000:00:0001:00:004629.751968.004278.7513122.75 0.00120.0003735.251313.753710.00 625.251147.502023-05-30 00:00:00
2023-05-3001:00:0002:00:004581.502033.753891.7511488.50 0.00119.5003523.501288.503984.75 769.251146.002023-05-30 01:00:00
2023-05-3002:00:0003:00:004551.001963.503725.5010141.00 0.00119.0003484.251263.753592.00 604.251141.752023-05-30 02:00:00
2023-05-3003:00:0004:00:004503.252090.503635.25 9170.25 0.00119.0003490.001272.504030.50 578.751132.502023-05-30 03:00:00
2023-05-3004:00:0005:00:004454.252105.253635.75 8735.75 2.25120.0003678.251275.004895.50 433.251136.002023-05-30 04:00:00
2023-05-3005:00:0006:00:004406.752134.752940.00 8419.75 407.75120.2504087.501289.255723.75 404.251142.252023-05-30 05:00:00
2023-05-3006:00:0007:00:004413.252227.502272.50 7531.00 2888.75128.2505010.751362.006525.252803.751144.502023-05-30 06:00:00
2023-05-3007:00:0008:00:004468.002276.501916.25 5507.25 8343.25137.0005275.501173.756905.755712.751156.752023-05-30 07:00:00
2023-05-3008:00:0009:00:004503.502152.501643.25 3647.7515893.25138.0005181.751196.256946.505079.501132.002023-05-30 08:00:00
2023-05-3009:00:0010:00:004544.502156.251285.00 2900.5023612.50135.0004707.501114.756384.502122.751115.002023-05-30 09:00:00
2023-05-3010:00:0011:00:004568.252085.251241.25 2729.5030341.75121.2503978.501095.504802.501279.001096.252023-05-30 10:00:00
2023-05-3011:00:0012:00:004618.752068.251053.25 3115.0035196.25119.0003759.751151.503762.25 774.001096.502023-05-30 11:00:00
2023-05-3012:00:0013:00:004612.251967.25 781.25 3496.2537030.00119.0003765.001296.753240.00 196.751099.752023-05-30 12:00:00
In [0]:

In [14]:
data %>% count(year(Time))
Out[14]:
A tibble: 9 × 2
year(Time)n
<dbl><int>
20158760
20168784
20178760
20188760
20198760
20208784
20218760
20228760
20233588
In [15]:
train <- data %>% filter(year(Time)<2021)
In [16]:
val <- data %>% filter(year(Time)==2021)
In [17]:
test <- data %>% filter(year(Time)>2021)
In [18]:
dim(train)
Out[18]:
  1. 52608
  2. 16
In [19]:
options(repr.plot.res = 200)
In [20]:
tidydf <- train %>%
    pivot_longer(names_to='Type', values_to='MWh', Biomasse:Sonstige_Konventionelle) %>%
    select(-c(Datum, Anfang, Ende))
In [21]:
ggplot(tidydf)+
    geom_line(aes(Time, MWh, color = Type)) + facet_wrap(Type~.)
Out[21]:
In [22]:
tidydf %>% 
            group_by(date = floor_date(Time, unit = "day"),Type) %>% 
            summarize(MWh = mean(MWh)) %>%
            ggplot() + geom_line(aes(date,MWh,color = Type)) + facet_wrap(~Type)
`summarise()` has grouped output by 'date'. You can override using the
`.groups` argument.
Out[22]:
In [23]:
tidydf %>% 
            group_by(date = floor_date(Time, unit = "month"),Type) %>%
            summarize(MWh = mean(MWh)) %>%
            ggplot() + geom_line(aes(date,MWh,color = Type)) + facet_wrap(~Type)
            #identity
`summarise()` has grouped output by 'date'. You can override using the
`.groups` argument.
Out[23]:

Todos 3rd Session¶

  • Select one of the types (e.g. Photovoltaik, Erdgas or Wind_Onshore)
  • What kinds of seasonality are detectable?
  • Is there a general trend on top of the seasonal pattern(s)?
  • Can you use this information to manually craft a prediction model?

Bonus:

  • How accurately does your manually created model predict the values in the validation set?

The following cell was generated by GPT-3.5 using this user prompt:

load lubridate

In [47]:
# Load the lubridate package
library(lubridate)
In [31]:
tidydf %>% filter(Type == "Photovoltaik") %>%
ggplot()+
geom_line(aes(Time,MWh), color = "red")
Out[31]:
In [0]:
#winter = 12, 1, 2
#spring = 3, 4 ,5
#summer = 6, 7 ,8
#autumn = 9, 10, 11
In [33]:
tidydf %>% filter(Type == "Photovoltaik") %>% 
group_by(date = floor_date(Time, unit = "month"),Type) %>%
            summarize(MWh = mean(MWh)) %>%
ggplot()+
geom_line(aes(date,MWh), color = "red")
`summarise()` has grouped output by 'date'. You can override using the
`.groups` argument.
Out[33]:
In [36]:
tidydf %>% filter(Type == "Photovoltaik") %>% 
group_by(date = floor_date(Time, unit = "month"),Type) %>%
            summarize(MWh = mean(MWh)) %>% group_by(month=floor_date
`summarise()` has grouped output by 'date'. You can override using the
`.groups` argument.
Out[36]:
A grouped_df: 72 × 3
dateTypeMWh
<dttm><chr><dbl>
2015-01-01Photovoltaik 752.2493
2015-02-01Photovoltaik2040.1849
2015-03-01Photovoltaik3847.3449
2015-04-01Photovoltaik6160.2625
2015-05-01Photovoltaik5929.5565
2015-06-01Photovoltaik6323.3656
2015-07-01Photovoltaik6609.5470
2015-08-01Photovoltaik6199.6925
2015-09-01Photovoltaik4481.2861
2015-10-01Photovoltaik2612.5466
2015-11-01Photovoltaik1578.4497
2015-12-01Photovoltaik1143.7224
2016-01-01Photovoltaik 879.4546
2016-02-01Photovoltaik1806.2453
2016-03-01Photovoltaik3249.1968
2016-04-01Photovoltaik5210.4660
2016-05-01Photovoltaik6339.7382
2016-06-01Photovoltaik6585.1951
2016-07-01Photovoltaik6643.5638
2016-08-01Photovoltaik6343.9425
2016-09-01Photovoltaik5345.0194
2016-10-01Photovoltaik2254.6785
2016-11-01Photovoltaik1417.9000
2016-12-01Photovoltaik1064.4335
2017-01-01Photovoltaik1073.1482
2017-02-01Photovoltaik2209.7753
2017-03-01Photovoltaik4348.0464
2017-04-01Photovoltaik5356.7413
2017-05-01Photovoltaik6882.1401
2017-06-01Photovoltaik7453.9729
⋮⋮⋮
2018-07-01Photovoltaik8288.8424
2018-08-01Photovoltaik6967.0218
2018-09-01Photovoltaik5651.8292
2018-10-01Photovoltaik3689.3745
2018-11-01Photovoltaik1626.3271
2018-12-01Photovoltaik 705.1929
2019-01-01Photovoltaik1001.3730
2019-02-01Photovoltaik3260.8144
2019-03-01Photovoltaik4107.6541
2019-04-01Photovoltaik7099.1146
2019-05-01Photovoltaik6751.5202
2019-06-01Photovoltaik8964.2944
2019-07-01Photovoltaik7707.7735
2019-08-01Photovoltaik7094.2107
2019-09-01Photovoltaik5436.3604
2019-10-01Photovoltaik3260.4044
2019-11-01Photovoltaik1456.0194
2019-12-01Photovoltaik1254.7285
2020-01-01Photovoltaik1474.6986
2020-02-01Photovoltaik2401.1110
2020-03-01Photovoltaik5523.6507
2020-04-01Photovoltaik8772.5955
2020-05-01Photovoltaik8328.6788
2020-06-01Photovoltaik7942.8160
2020-07-01Photovoltaik8446.6720
2020-08-01Photovoltaik7309.8696
2020-09-01Photovoltaik6430.2490
2020-10-01Photovoltaik2903.1114
2020-11-01Photovoltaik2106.9997
2020-12-01Photovoltaik 920.7248
In [51]:
tidydf %>% filter(Type == "Photovoltaik") %>% 
group_by(date = floor_date(Time, unit = "day"),Type) %>% 
            summarize(MWh = mean(MWh)) %>% mutate(day = yday(date), month = months(date), year = format(date, format = "%Y")) %>%
group_by(month)%>%
summarize(MWh mean(MWh))%>%
ggplot()+
geom_line(aes(month,MWh, color = year))
`summarise()` has grouped output by 'date'. You can override using the
`.groups` argument.
Warning message:
“Returning more (or less) than 1 row per `summarise()` group was deprecated in
dplyr 1.1.0.
ℹ Please use `reframe()` instead.
ℹ When switching from `summarise()` to `reframe()`, remember that `reframe()`
  always returns an ungrouped data frame and adjust accordingly.”
`summarise()` has grouped output by 'month'. You can override using the
`.groups` argument.
Don't know how to automatically pick scale for object of type <function>.
Defaulting to continuous.
ERROR while rich displaying an object: Error in `geom_line()`:
! Problem while computing aesthetics.
ℹ Error occurred in the 1st layer.
Caused by error in `compute_aesthetics()`:
! Aesthetics are not valid data columns.
✖ The following aesthetics are invalid:
✖ `colour = year`
ℹ Did you mistype the name of a data column or forget to add `after_stat()`?

Traceback:
1. tryCatch(withCallingHandlers({
 .     if (!mime %in% names(repr::mime2repr)) 
 .         stop("No repr_* for mimetype ", mime, " in repr::mime2repr")
 .     rpr <- repr::mime2repr[[mime]](obj)
 .     if (is.null(rpr)) 
 .         return(NULL)
 .     prepare_content(is.raw(rpr), rpr)
 . }, error = error_handler), error = outer_handler)
2. tryCatchList(expr, classes, parentenv, handlers)
3. tryCatchOne(expr, names, parentenv, handlers[[1L]])
4. doTryCatch(return(expr), name, parentenv, handler)
5. withCallingHandlers({
 .     if (!mime %in% names(repr::mime2repr)) 
 .         stop("No repr_* for mimetype ", mime, " in repr::mime2repr")
 .     rpr <- repr::mime2repr[[mime]](obj)
 .     if (is.null(rpr)) 
 .         return(NULL)
 .     prepare_content(is.raw(rpr), rpr)
 . }, error = error_handler)
6. repr::mime2repr[[mime]](obj)
7. repr_text.default(obj)
8. paste(capture.output(print(obj)), collapse = "\n")
9. capture.output(print(obj))
10. withVisible(...elt(i))
11. print(obj)
12. print.ggplot(obj)
13. ggplot_build(x)
14. ggplot_build.ggplot(x)
15. by_layer(function(l, d) l$compute_aesthetics(d, plot), layers, 
  .     data, "computing aesthetics")
16. try_fetch(for (i in seq_along(data)) {
  .     out[[i]] <- f(l = layers[[i]], d = data[[i]])
  . }, error = function(cnd) {
  .     cli::cli_abort(c("Problem while {step}.", i = "Error occurred in the {ordinal(i)} layer."), 
  .         call = layers[[i]]$constructor, parent = cnd)
  . })
17. tryCatch(withCallingHandlers(expr, condition = function(cnd) {
  .     {
  .         .__handler_frame__. <- TRUE
  .         .__setup_frame__. <- frame
  .         if (inherits(cnd, "message")) {
  .             except <- c("warning", "error")
  .         }
  .         else if (inherits(cnd, "warning")) {
  .             except <- "error"
  .         }
  .         else {
  .             except <- ""
  .         }
  .     }
  .     while (!is_null(cnd)) {
  .         if (inherits(cnd, "error")) {
  .             out <- handlers[[1L]](cnd)
  .             if (!inherits(out, "rlang_zap")) 
  .                 throw(out)
  .         }
  .         inherit <- .subset2(.subset2(cnd, "rlang"), "inherit")
  .         if (is_false(inherit)) {
  .             return()
  .         }
  .         cnd <- .subset2(cnd, "parent")
  .     }
  . }), stackOverflowError = handlers[[1L]])
18. tryCatchList(expr, classes, parentenv, handlers)
19. tryCatchOne(expr, names, parentenv, handlers[[1L]])
20. doTryCatch(return(expr), name, parentenv, handler)
21. withCallingHandlers(expr, condition = function(cnd) {
  .     {
  .         .__handler_frame__. <- TRUE
  .         .__setup_frame__. <- frame
  .         if (inherits(cnd, "message")) {
  .             except <- c("warning", "error")
  .         }
  .         else if (inherits(cnd, "warning")) {
  .             except <- "error"
  .         }
  .         else {
  .             except <- ""
  .         }
  .     }
  .     while (!is_null(cnd)) {
  .         if (inherits(cnd, "error")) {
  .             out <- handlers[[1L]](cnd)
  .             if (!inherits(out, "rlang_zap")) 
  .                 throw(out)
  .         }
  .         inherit <- .subset2(.subset2(cnd, "rlang"), "inherit")
  .         if (is_false(inherit)) {
  .             return()
  .         }
  .         cnd <- .subset2(cnd, "parent")
  .     }
  . })
22. f(l = layers[[i]], d = data[[i]])
23. l$compute_aesthetics(d, plot)
24. compute_aesthetics(..., self = self)
25. cli::cli_abort(c("Aesthetics are not valid data columns.", x = "The following aesthetics are invalid:", 
  .     issues, i = "Did you mistype the name of a data column or forget to add {.fn after_stat}?"))
26. rlang::abort(message, ..., call = call, use_cli_format = TRUE, 
  .     .frame = .frame)
27. signal_abort(cnd, .file)
28. signalCondition(cnd)
29. (function (cnd) 
  . {
  .     {
  .         .__handler_frame__. <- TRUE
  .         .__setup_frame__. <- frame
  .         if (inherits(cnd, "message")) {
  .             except <- c("warning", "error")
  .         }
  .         else if (inherits(cnd, "warning")) {
  .             except <- "error"
  .         }
  .         else {
  .             except <- ""
  .         }
  .     }
  .     while (!is_null(cnd)) {
  .         if (inherits(cnd, "error")) {
  .             out <- handlers[[1L]](cnd)
  .             if (!inherits(out, "rlang_zap")) 
  .                 throw(out)
  .         }
  .         inherit <- .subset2(.subset2(cnd, "rlang"), "inherit")
  .         if (is_false(inherit)) {
  .             return()
  .         }
  .         cnd <- .subset2(cnd, "parent")
  .     }
  . })(structure(list(message = structure("Aesthetics are not valid data columns.", names = ""), 
  .     trace = structure(list(call = list(IRkernel::main(), kernel$run(), 
  .         handle_shell(), executor$execute(msg), tryCatch(evaluate(request$content$code, 
  .             envir = .GlobalEnv, output_handler = oh, stop_on_error = 1L), 
  .             interrupt = function(cond) {
  .                 log_debug("Interrupt during execution")
  .                 interrupted <<- TRUE
  .             }, error = .self$handle_error), tryCatchList(expr, 
  .             classes, parentenv, handlers), tryCatchOne(tryCatchList(expr, 
  .             names[-nh], parentenv, handlers[-nh]), names[nh], 
  .             parentenv, handlers[[nh]]), doTryCatch(return(expr), 
  .             name, parentenv, handler), tryCatchList(expr, names[-nh], 
  .             parentenv, handlers[-nh]), tryCatchOne(expr, names, 
  .             parentenv, handlers[[1L]]), doTryCatch(return(expr), 
  .             name, parentenv, handler), evaluate(request$content$code, 
  .             envir = .GlobalEnv, output_handler = oh, stop_on_error = 1L), 
  .         evaluate_call(expr, parsed$src[[i]], envir = envir, enclos = enclos, 
  .             debug = debug, last = i == length(out), use_try = stop_on_error != 
  .                 2L, keep_warning = keep_warning, keep_message = keep_message, 
  .             log_echo = log_echo, log_warning = log_warning, output_handler = output_handler, 
  .             include_timing = include_timing), handle(pv <- withCallingHandlers(withVisible(value_fun(ev$value, 
  .             ev$visible)), warning = wHandler, error = eHandler, 
  .             message = mHandler)), try(f, silent = TRUE), tryCatch(expr, 
  .             error = function(e) {
  .                 call <- conditionCall(e)
  .                 if (!is.null(call)) {
  .                   if (identical(call[[1L]], quote(doTryCatch))) 
  .                     call <- sys.call(-4L)
  .                   dcall <- deparse(call, nlines = 1L)
  .                   prefix <- paste("Error in", dcall, ": ")
  .                   LONG <- 75L
  .                   sm <- strsplit(conditionMessage(e), "\n")[[1L]]
  .                   w <- 14L + nchar(dcall, type = "w") + nchar(sm[1L], 
  .                     type = "w")
  .                   if (is.na(w)) 
  .                     w <- 14L + nchar(dcall, type = "b") + nchar(sm[1L], 
  .                       type = "b")
  .                   if (w > LONG) 
  .                     prefix <- paste0(prefix, "\n  ")
  .                 }
  .                 else prefix <- "Error : "
  .                 msg <- paste0(prefix, conditionMessage(e), "\n")
  .                 .Internal(seterrmessage(msg[1L]))
  .                 if (!silent && isTRUE(getOption("show.error.messages"))) {
  .                   cat(msg, file = outFile)
  .                   .Internal(printDeferredWarnings())
  .                 }
  .                 invisible(structure(msg, class = "try-error", 
  .                   condition = e))
  .             }), tryCatchList(expr, classes, parentenv, handlers), 
  .         tryCatchOne(expr, names, parentenv, handlers[[1L]]), 
  .         doTryCatch(return(expr), name, parentenv, handler), withCallingHandlers(withVisible(value_fun(ev$value, 
  .             ev$visible)), warning = wHandler, error = eHandler, 
  .             message = mHandler), withVisible(value_fun(ev$value, 
  .             ev$visible)), value_fun(ev$value, ev$visible), prepare_mimebundle_kernel(obj, 
  .             .self$handle_display_error), prepare_mimebundle(obj, 
  .             "text/plain", error_handler = handle_display_error), 
  .         filter_map(mimetypes, function(mime) {
  .             tryCatch(withCallingHandlers({
  .                 if (!mime %in% names(repr::mime2repr)) 
  .                   stop("No repr_* for mimetype ", mime, " in repr::mime2repr")
  .                 rpr <- repr::mime2repr[[mime]](obj)
  .                 if (is.null(rpr)) 
  .                   return(NULL)
  .                 prepare_content(is.raw(rpr), rpr)
  .             }, error = error_handler), error = outer_handler)
  .         }), Filter(Negate(is.null), sapply(x, f, simplify = simplify)), 
  .         unlist(lapply(x, f)), lapply(x, f), sapply(x, f, simplify = simplify), 
  .         lapply(X = X, FUN = FUN, ...), FUN(X[[i]], ...), tryCatch(withCallingHandlers({
  .             if (!mime %in% names(repr::mime2repr)) 
  .                 stop("No repr_* for mimetype ", mime, " in repr::mime2repr")
  .             rpr <- repr::mime2repr[[mime]](obj)
  .             if (is.null(rpr)) 
  .                 return(NULL)
  .             prepare_content(is.raw(rpr), rpr)
  .         }, error = error_handler), error = outer_handler), tryCatchList(expr, 
  .             classes, parentenv, handlers), tryCatchOne(expr, 
  .             names, parentenv, handlers[[1L]]), doTryCatch(return(expr), 
  .             name, parentenv, handler), withCallingHandlers({
  .             if (!mime %in% names(repr::mime2repr)) 
  .                 stop("No repr_* for mimetype ", mime, " in repr::mime2repr")
  .             rpr <- repr::mime2repr[[mime]](obj)
  .             if (is.null(rpr)) 
  .                 return(NULL)
  .             prepare_content(is.raw(rpr), rpr)
  .         }, error = error_handler), repr::mime2repr[[mime]](obj), 
  .         repr_text.default(obj), paste(capture.output(print(obj)), 
  .             collapse = "\n"), capture.output(print(obj)), withVisible(...elt(i)), 
  .         print(obj), print.ggplot(obj), ggplot_build(x), ggplot_build.ggplot(x), 
  .         by_layer(function(l, d) l$compute_aesthetics(d, plot), 
  .             layers, data, "computing aesthetics"), try_fetch(for (i in seq_along(data)) {
  .             out[[i]] <- f(l = layers[[i]], d = data[[i]])
  .         }, error = function(cnd) {
  .             cli::cli_abort(c("Problem while {step}.", i = "Error occurred in the {ordinal(i)} layer."), 
  .                 call = layers[[i]]$constructor, parent = cnd)
  .         }), tryCatch(withCallingHandlers(expr, condition = function(cnd) {
  .             {
  .                 .__handler_frame__. <- TRUE
  .                 .__setup_frame__. <- frame
  .                 if (inherits(cnd, "message")) {
  .                   except <- c("warning", "error")
  .                 }
  .                 else if (inherits(cnd, "warning")) {
  .                   except <- "error"
  .                 }
  .                 else {
  .                   except <- ""
  .                 }
  .             }
  .             while (!is_null(cnd)) {
  .                 if (inherits(cnd, "error")) {
  .                   out <- handlers[[1L]](cnd)
  .                   if (!inherits(out, "rlang_zap")) 
  .                     throw(out)
  .                 }
  .                 inherit <- .subset2(.subset2(cnd, "rlang"), "inherit")
  .                 if (is_false(inherit)) {
  .                   return()
  .                 }
  .                 cnd <- .subset2(cnd, "parent")
  .             }
  .         }), stackOverflowError = handlers[[1L]]), tryCatchList(expr, 
  .             classes, parentenv, handlers), tryCatchOne(expr, 
  .             names, parentenv, handlers[[1L]]), doTryCatch(return(expr), 
  .             name, parentenv, handler), withCallingHandlers(expr, 
  .             condition = function(cnd) {
  .                 {
  .                   .__handler_frame__. <- TRUE
  .                   .__setup_frame__. <- frame
  .                   if (inherits(cnd, "message")) {
  .                     except <- c("warning", "error")
  .                   }
  .                   else if (inherits(cnd, "warning")) {
  .                     except <- "error"
  .                   }
  .                   else {
  .                     except <- ""
  .                   }
  .                 }
  .                 while (!is_null(cnd)) {
  .                   if (inherits(cnd, "error")) {
  .                     out <- handlers[[1L]](cnd)
  .                     if (!inherits(out, "rlang_zap")) 
  .                       throw(out)
  .                   }
  .                   inherit <- .subset2(.subset2(cnd, "rlang"), 
  .                     "inherit")
  .                   if (is_false(inherit)) {
  .                     return()
  .                   }
  .                   cnd <- .subset2(cnd, "parent")
  .                 }
  .             }), f(l = layers[[i]], d = data[[i]]), l$compute_aesthetics(d, 
  .             plot), compute_aesthetics(..., self = self), cli::cli_abort(c("Aesthetics are not valid data columns.", 
  .             x = "The following aesthetics are invalid:", issues, 
  .             i = "Did you mistype the name of a data column or forget to add {.fn after_stat}?")), 
  .         rlang::abort(message, ..., call = call, use_cli_format = TRUE, 
  .             .frame = .frame)), parent = c(0L, 1L, 2L, 3L, 4L, 
  .     5L, 6L, 7L, 6L, 9L, 10L, 4L, 12L, 13L, 14L, 15L, 16L, 17L, 
  .     18L, 13L, 13L, 13L, 22L, 23L, 24L, 25L, 26L, 26L, 25L, 29L, 
  .     30L, 31L, 32L, 33L, 34L, 31L, 31L, 31L, 38L, 38L, 40L, 38L, 
  .     38L, 43L, 43L, 45L, 46L, 47L, 48L, 49L, 50L, 47L, 46L, 53L, 
  .     54L, 55L, 56L), visible = c(TRUE, TRUE, TRUE, TRUE, TRUE, 
  .     TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, 
  .     TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, 
  .     TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, 
  .     TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, 
  .     TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, 
  .     FALSE, FALSE), namespace = c("IRkernel", NA, "IRkernel", 
  .     NA, "base", "base", "base", "base", "base", "base", "base", 
  .     "evaluate", "evaluate", "evaluate", "base", "base", "base", 
  .     "base", "base", "base", "base", "IRkernel", "IRkernel", "IRdisplay", 
  .     "IRdisplay", "base", "base", "base", "base", "base", "IRdisplay", 
  .     "base", "base", "base", "base", "base", NA, "repr", "base", 
  .     "utils", "base", "base", "ggplot2", "ggplot2", "ggplot2", 
  .     "ggplot2", "rlang", "base", "base", "base", "base", "base", 
  .     "ggplot2", NA, "ggplot2", "cli", "rlang"), scope = c("::", 
  .     NA, "local", NA, "::", "local", "local", "local", "local", 
  .     "local", "local", "::", ":::", "local", "::", "::", "local", 
  .     "local", "local", "::", "::", "local", ":::", "::", ":::", 
  .     "::", "::", "::", "::", "::", "local", "::", "local", "local", 
  .     "local", "::", NA, ":::", "::", "::", "::", "::", ":::", 
  .     "::", ":::", ":::", "::", "::", "local", "local", "local", 
  .     "::", "local", NA, "local", "::", "::"), error_frame = c(FALSE, 
  .     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
  .     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
  .     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
  .     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
  .     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
  .     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, 
  .     FALSE, FALSE)), row.names = c(NA, -57L), version = 2L, class = c("rlang_trace", 
  .     "rlib_trace", "tbl", "data.frame")), parent = NULL, body = c(x = "The following aesthetics are invalid:", 
  .     x = "`colour = year`", i = "Did you mistype the name of a data column or forget to add `after_stat()`?"
  .     ), rlang = list(inherit = TRUE), call = compute_aesthetics(..., 
  .         self = self), use_cli_format = TRUE), class = c("rlang_error", 
  . "error", "condition")))
30. handlers[[1L]](cnd)
31. cli::cli_abort(c("Problem while {step}.", i = "Error occurred in the {ordinal(i)} layer."), 
  .     call = layers[[i]]$constructor, parent = cnd)
32. rlang::abort(message, ..., call = call, use_cli_format = TRUE, 
  .     .frame = .frame)
33. signal_abort(cnd, .file)
In [0]:

In [0]: