ggplot geom_tile 在 ggplotly 中失真

ggplot geom_tile is distorted in ggplotly

我正在尝试将使用 ggplot 构建的 geom_tile 地块转换为 ggplotly。但是,瓷砖在情节中扭曲了。 geom_raster.

也会出现同样的问题

展示:

library(ggplot2)
library(plotly)
set.seed(1)
n <- 10
X <- data.frame(xcoord = sample(1:10, n, replace = TRUE),
                ycoord = sample(1:10, n, replace = TRUE),
                value = runif(n))
gg <- ggplot(X) + geom_tile(aes(x = xcoord, y = ycoord, fill = value))
ggplotly(gg)

查看绘图代码 here (excerpt below),似乎栅格仅针对数据集中可用的任何 x 和 y 值定义 - 无论中间发生什么,都在其余的绘图代码中.

geom2trace.GeomTile <- function(data, params, p) {
  x <- sort(unique(data[["x"]]))
  y <- sort(unique(data[["y"]]))
  # make sure we're dealing with a complete grid
  g <- expand.grid(x = x, y = y)
  g$order <- seq_len(nrow(g))
  g <- merge(g, data, by = c("x", "y"), all.x = TRUE)
  g <- g[order(g$order), ]
...

对于示例数据,此代码生成以下数据,其中灰色区域为 NA,空白区域只是未定义。所有 distortions/stretching 都发生在未定义的区域。

ggplot(g, aes(x = x, y = y, fill = value)) + geom_tile()

有了这个,一种可能的解决方法(在 plotly 包之外)是手动确保在整个 x/y 范围内有 (NA) 数据可用,因此 expand.grid 生成足够密集的网格当情节被翻译成 plotly.

set.seed(1)
X1 <- data.frame(xcoord = c(sample(1:10, n, replace = TRUE), 1:10),
                ycoord = c(sample(1:10, n, replace = TRUE), 1:10),
                value = c(runif(n), rep(NA, 10)))
gg1 <- ggplot(X1) + geom_tile(aes(x = xcoord, y = ycoord, fill = value))
ggplotly(gg1)

更新

虽然上面的例子表明数据集中的任何 x 和 y 都有一个单一的值就足够了,但我还将添加一个可以说更清晰的解决方案,正如 Waldi 所建议的在评论中。通过(自动)提前生成完整的网格,可以减少对情节翻译怪癖的依赖。对于不为1的网格间距,当然需要调整顺序。

# X: original dataframe as defined in the question
X2 <- tidyr::expand_grid(
  xcoord = seq(min(X$xcoord), max(X$xcoord)), 
  ycoord = seq(min(X$ycoord),max(X$ycoord))
  ) %>%    
  dplyr::left_join(X, by=c('xcoord','ycoord'))
gg2 <- ggplot(X2) + geom_tile(aes(x = xcoord, y = ycoord, fill = value))
ggplotly(gg2)