Skip to content

Feature request: drawing ordering from layer to layer instead of panel to panel #6396

Closed as not planned
@Yunuuuu

Description

@Yunuuuu

Currently, ggplot2 draws each facet panel sequentially, which means the complete drawing of one panel is finished before the next begins. This causes issues when a geom spans across multiple facet panels—for example, in cases like tree structures (e.g., dendrograms) that connect elements across panels.

Image

Under the current rendering logic, parts of such layers can be hidden or clipped because layers are drawn panel-by-panel rather than layer-by-layer across panels. It's hard for us to create layer like above dendrogram.

To address this, I’ve experimented with creating a custom grob that allows communication between different viewports. Specifically, I built a channelGrob() object that emits "signals" from different panels and connects them with a line once all signals are available:

# pak::pak("Yunuuuu/ggalign")
library(ggalign)
# here we create a new channel, we will emit two singals
# when drawing: we just add a line between the two signals
channel <- channelGrob(function(locations) {
    loc1 <- .subset2(locations, 1L)
    loc2 <- .subset2(locations, 2L)
    grid::segmentsGrob(loc1$x, loc1$y, loc2$x, loc2$y)
})
gt <- gtable::gtable(unit(1:2, c("cm")), unit(5, "cm"))
gt <- gtable::gtable_add_grob(
    gt,
    list(
        grid::rectGrob(gp = gpar(color = "black", fill = NA)),
        channel$signal(0.5, 0.5, "npc")
    ),
    t = 1, l = 1, name = c("rect1", "signal1")
)
gt <- gtable::gtable_add_grob(
    gt,
    list(
        grid::rectGrob(gp = gpar(color = "red", fill = NA)),
        channel$signal(0.5, 0.5, "npc")
    ),
    t = 1, l = 2, name = c("rect2", "signal2")
)
grid::grid.newpage()
grid::grid.draw(gt)

Image

This works in isolation, but integrating it into ggplot2’s layer system is quite difficult. The issue is that this kind of grob needs to wait for multiple signals before drawing, and it must be drawn after all contributing panels have emitted their signal. This behavior conflicts with ggplot2’s panel drawing order since it will override other geom layers that were already drawn in those panels

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions