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 @@
+
+
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 @@
+
+
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")