Skip to content

plot(post_treatment_periods = N) length-mismatch with frequency = "weekly" and treatment_end_date #225

Description

@rkabariti

Bug description

Calling plot() on a GeoLift object with treatment_end_date, frequency = "weekly", and post_treatment_periods > 0 raises a length-mismatch error in $<-.data.frame. The same call pattern works correctly with frequency = "daily", isolating the issue to the weekly code path.

The Time vector passed to the plot's internal data frame is built with treatment_end_time + post_treatment_periods elements, but the data frame it's assigned to only has treatment_end_time rows. The mismatch is consistently equal to post_treatment_periods across runs:

dataset treatment_end_time post_treatment_periods Time length data rows
Bundled (weekly-aggregated) 16 2 18 16
Private weekly 72 2 74 72
Private weekly 74 2 76 74
Private weekly 70 4 74 70

Doc note (separate, minor): the Measuring Lagged Effects blog post refers to the argument as post_test_treatment_periods; the actual argument is post_treatment_periods. Worth aligning while this is being touched.

Session information

R version 4.5.3 (2026-03-11)
Platform: aarch64-apple-darwin20
Running under: macOS Tahoe 26.5

Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.1

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

time zone: America/Sao_Paulo
tzcode source: internal

attached base packages:
[1] stats graphics grDevices utils datasets methods base

other attached packages:
[1] ggplot2_4.0.3 tidyr_1.3.2 dplyr_1.2.1 GeoLift_2.7.5

loaded via a namespace (and not attached):
[1] gtable_0.3.6 xfun_0.57 remotes_2.5.0 GGally_2.4.0
[5] lattice_0.22-9 numDeriv_2016.8-1.1 quadprog_1.5-8 vctrs_0.7.3
[9] tools_4.5.3 generics_0.1.4 CausalImpact_1.4.1 augsynth_0.2.0
[13] curl_7.1.0 parallel_4.5.3 sandwich_3.1-1 proxy_0.4-29
[17] tibble_3.3.1 xts_0.14.2 pkgconfig_2.0.3 MarketMatching_1.2.1
[21] Matrix_1.7-5 RColorBrewer_1.1-3 S7_0.2.2 rngtools_1.5.2
[25] stringmagic_1.2.0 assertthat_0.2.1 lifecycle_1.0.5 compiler_4.5.3
[29] farver_2.1.2 stringr_1.6.0 progress_1.2.3 codetools_0.2-20
[33] gsynth_1.4.0 Formula_1.2-5 crayon_1.5.3 pillar_1.11.1
[37] panelView_1.3.0 MASS_7.3-65 doRNG_1.8.6.3 iterators_1.0.14
[41] abind_1.4-8 foreach_1.5.2 nlme_3.1-169 parallelly_1.47.0
[45] ggstats_0.13.0 tidyselect_1.2.1 digest_0.6.39 mvtnorm_1.3-7
[49] stringi_1.8.7 future_1.70.0 reshape2_1.4.5 purrr_1.2.2
[53] listenv_0.10.1 labeling_0.4.3 grid_4.5.3 cli_3.6.6
[57] magrittr_2.0.5 utf8_1.2.6 future.apply_1.20.2 withr_3.0.2
[61] dreamerr_1.5.0 prettyunits_1.2.0 scales_1.4.0 globals_0.19.1
[65] gridExtra_2.3 Boom_0.9.16 hms_1.1.4 zoo_1.8-15
[69] evaluate_1.0.5 knitr_1.51 BoomSpikeSlab_1.2.7 dtw_1.23-2
[73] doParallel_1.0.17 fixest_0.14.0 fect_2.2.0 rlang_1.2.0
[77] Rcpp_1.1.1 glue_1.8.1 directlabels_2025.6.24 osqp_1.0.0
[81] rstudioapi_0.18.0 R6_2.6.1 plyr_1.8.9 bsts_0.9.11

Reproduction steps

The bundled GeoLift_Test dataset is daily, so aggregating to weekly first gives a self-contained reproduction:

library(GeoLift)
library(dplyr)

data(GeoLift_Test)

# Aggregate the bundled daily data to weekly
weekly <- GeoLift_Test |>
  mutate(date = as.Date(date),
         week = as.Date(cut(date, breaks = "week", start.on.monday = TRUE))) |>
  group_by(location, week) |>
  summarise(Y = sum(Y), .groups = "drop") |>
  rename(date = week) |>
  mutate(date = format(date, "%Y-%m-%d"))

GTD_w <- GeoDataRead(data = weekly, date_id = "date",
                     location_id = "location", Y_id = "Y",
                     format = "yyyy-mm-dd")

n_periods <- max(GTD_w$time)        # 16
GT_w <- GeoLift(Y_id = "Y", data = GTD_w,
                locations = c("chicago", "portland"),
                treatment_start_time = n_periods - 4,
                treatment_end_time = n_periods)

last_date <- max(weekly$date)

# Errors:
plot(GT_w, type = "ATT",
     treatment_end_date = last_date,
     frequency = "weekly",
     post_treatment_periods = 2)

Error output:

Error in `$<-.data.frame`(`*tmp*`, "Time", value = c(18624, 18631, 18638,  :
  replacement has 18 rows, data has 16

For contrast, the same pattern with the original daily data renders correctly:

GTD <- GeoDataRead(data = GeoLift_Test, date_id = "date",
                   location_id = "location", Y_id = "Y",
                   format = "yyyy-mm-dd")

GT <- GeoLift(Y_id = "Y", data = GTD,
              locations = c("chicago", "portland"),
              treatment_start_time = 91, treatment_end_time = 105)

plot(GT, type = "ATT",
     treatment_end_date = "2022-03-08",   # date corresponding to t = 105
     frequency = "daily",
     post_treatment_periods = 5)

Expected behavior

The plot should render with a dated x-axis and the trailing post_treatment_periods weeks visually delineated as the post-treatment window — matching the behavior documented in the Measuring Lagged Effects blog post and matching the behavior already produced when frequency = "daily".

A working alternative on the same fit (without dated axis) renders correctly:

plot(GT_w, type = "ATT", post_treatment_periods = 2)

So the underlying data is sufficient for the post-treatment window; the failure is specific to the dated-axis weekly code path.

Additional context

Workaround: omitting treatment_end_date and frequency produces a correct plot on weekly data, but with integer timestamps on the x-axis instead of dates.

Suspected location: the $<-.data.frame call is assigning a Time column of treatment_end_time + post_treatment_periods length to a data frame of treatment_end_time rows, consistently off by exactly post_treatment_periods. Whatever extends the Time sequence to cover the post-treatment window in the weekly code path isn't applied to the data frame being labeled.

Happy to test any patches or provide additional repros — also have a private weekly dataset (74 periods) where the same pattern shows up across multiple (treatment_end_time, post_treatment_periods) combinations if useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions