diff --git a/NEWS.md b/NEWS.md index f59f85f..5b400cc 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,11 +2,12 @@ ### Bug fixes -- Fix missing "hypothesis" attribute for `aggr_es` objects (#43) +- Fix missing "hypothesis" attribute for `aggr_es` objects. (#43) +- Fix dodge misalignment between points and lines with multi fixest objects. (#44) ### Internals -- Replace `ggh4x` dependency with `legendry` (#41 @teunbrand) +- Replace `ggh4x` dependency with `legendry`. (#41 @teunbrand) ### Misc diff --git a/R/ggiplot.R b/R/ggiplot.R index 4578291..d70511b 100644 --- a/R/ggiplot.R +++ b/R/ggiplot.R @@ -145,23 +145,23 @@ ggiplot = function( has_groups = (!is.null(attributes(data)[["has_groups"]]) && isTRUE(attributes(data)[["has_groups"]])) if (isTRUE(has_groups)) { - key <- unique(data[c("x", "group_var")]) - key <- key[order(key[["group_var"]], key[["x"]]), , drop = FALSE] - xlimits <- as.character(key[["x"]]) + key = unique(data[c("x", "group_var")]) + key = key[order(key[["group_var"]], key[["x"]]), , drop = FALSE] + xlimits = as.character(key[["x"]]) - rle <- rle(as.character(key[["group_var"]])) - keep <- nzchar(rle$values) - end <- cumsum(rle$lengths) - start <- end - rle$lengths + 1L + rle = rle(as.character(key[["group_var"]])) + keep = nzchar(rle$values) + end = cumsum(rle$lengths) + start = end - rle$lengths + 1L - key <- legendry::key_range_manual( + key = legendry::key_range_manual( start = xlimits[start[keep]], end = xlimits[end[keep]], name = rle$values[keep], level = 1L ) - data[["group_var"]] <- NULL + data[["group_var"]] = NULL } yrange = range(c(data[["ci_low"]], data[["ci_high"]]), na.rm = TRUE) @@ -343,10 +343,15 @@ ggiplot = function( if (geom_style == "ribbon" || pt.join) { if (multi_style == "dodge") { if (length(ci_level) == 1) { - geom_line( - aes(group = paste0(.data$group, .data$id)), - position = position_dodge(width = ci.width) - ) + if (identical(data$group, data$id)) { + geom_line(position = position_dodge2(width = ci.width, padding = ci.width)) + } else { + geom_line( + aes(group = paste0(.data$group, .data$id)), # catch for complex split combos + position = position_dodge2(width = ci.width, padding = ci.width) + ) + + } } else { geom_line( data = ~ subset(.x, ci_level == max(ci_level)), diff --git a/inst/tinytest/_tinysnapshot/ggiplot_multi_complex.svg b/inst/tinytest/_tinysnapshot/ggiplot_multi_complex.svg index d731b24..d74b0e1 100644 --- a/inst/tinytest/_tinysnapshot/ggiplot_multi_complex.svg +++ b/inst/tinytest/_tinysnapshot/ggiplot_multi_complex.svg @@ -30,156 +30,156 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -191,14 +191,14 @@ - - - - --10 --5 -0 -5 + + + + +-10 +-5 +0 +5 time_to_treatment Estimate and 95% Conf. Int. diff --git a/inst/tinytest/_tinysnapshot/ggiplot_multi_single_ribbon.svg b/inst/tinytest/_tinysnapshot/ggiplot_multi_single_ribbon.svg index 68b98ca..aa83499 100644 --- a/inst/tinytest/_tinysnapshot/ggiplot_multi_single_ribbon.svg +++ b/inst/tinytest/_tinysnapshot/ggiplot_multi_single_ribbon.svg @@ -30,52 +30,52 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -85,14 +85,14 @@ - - - - --10 --5 -0 -5 + + + + +-10 +-5 +0 +5 time_to_treatment Estimate and 95% Conf. Int. diff --git a/inst/tinytest/_tinysnapshot/ggiplot_multi_sw_pt_join1.svg b/inst/tinytest/_tinysnapshot/ggiplot_multi_sw_pt_join1.svg new file mode 100644 index 0000000..ede9fc0 --- /dev/null +++ b/inst/tinytest/_tinysnapshot/ggiplot_multi_sw_pt_join1.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +-3 +0 +3 +6 +9 + + + + + + + + + + +2 +4 +6 +8 +10 +period +Estimate and 95% Conf. Int. + +group + + + + + + + + + + + + +fixef: 1 +fixef: period +fixef: id +Effect on y + + diff --git a/inst/tinytest/_tinysnapshot/ggiplot_multi_sw_pt_join2.svg b/inst/tinytest/_tinysnapshot/ggiplot_multi_sw_pt_join2.svg new file mode 100644 index 0000000..a6ce368 --- /dev/null +++ b/inst/tinytest/_tinysnapshot/ggiplot_multi_sw_pt_join2.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +-3 +0 +3 +6 +9 + + + + + + + + + + +2 +4 +6 +8 +10 +period +Estimate and 95% Conf. Int. + +group + + + + + + + + + + + + +fixef: 1 +fixef: id +fixef: period +Effect on y + + diff --git a/inst/tinytest/test_ggiplot.R b/inst/tinytest/test_ggiplot.R index c0cd13f..6f0462c 100644 --- a/inst/tinytest/test_ggiplot.R +++ b/inst/tinytest/test_ggiplot.R @@ -191,3 +191,17 @@ p19b = ggiplot( ) expect_snapshot_plot(p19a, label = "ggiplot_multi_complex_kitchen_iid") expect_snapshot_plot(p19b, label = "ggiplot_multi_complex_kitchen_iid") + +# +# Making sure pt.join works with sw() and is not sensitive to ordering + +# https://github.com/grantmcdermott/ggfixest/issues/40#issuecomment-2444436162 +base_did$y2 = base_did$y*1.5 +base_did$y3 = base_did$y*2 + +m20a = fixest::feols(y ~ x1 + i(period, treat, 5) | sw0(period, id), base_did) +m20b = fixest::feols(y ~ x1 + i(period, treat, 5) | sw0(id, period), base_did) +p20a = ggiplot(m20a, pt.join = TRUE) +p20b = ggiplot(m20b, pt.join = TRUE) +expect_snapshot_plot(p20a, label = "ggiplot_multi_sw_pt_join1") +expect_snapshot_plot(p20b, label = "ggiplot_multi_sw_pt_join2")