点之间的坡率线段/直线:ggforce geom_link2()B/c plotly的替代方法不起作用

p4rjhz4m  于 2022-12-06  发布在  其他
关注(0)|答案(1)|浏览(96)

我使用ggforce包中的geom_link2制作了一个点之间带有渐变线段的ggplot,它完成了我想要的任务:

但是当我通过ggplotly()传输它时,我收到Warning: geom_GeomPathInterpolate() has yet to be implemented in plotly.的警告,它打印出来的时候没有这些线。我试着在GitHub上发布这个geom,但是不确定我做的是否正确。有没有其他方法可以在ggplot中生成与ggplot兼容的渐变线/线段?谢谢!

# Practice data

library(ggplot2)
library(plotly)
library(ggforce)

# df
data <- structure(list( Percent = c(0.32, 0.23, 0.75, 0.25, 0.482, 0.421, 0.5114, 0.3423, 0.27, 0.4324, 0.347, 0.377, 0.26, 
0.375, 0.18604, 0.241378, 0.3095, 0.348837209, 0.33333, 0.1875, 0.2820, 0.65, 0.72, 0.75, 0.81, 0.87, 0.8244), finalpoint = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
NA, NA, NA, NA, 0.8244), date = structure(c(18262, 18293, 18322, 18353, 18383, 18414, 18444, 18475, 18506, 18536, 
18567, 18597, 18628, 18659, 18687, 18718, 18748, 18779, 18809, 18840, 18871, 18901, 18932, 18962, 18993, 19024, 19052), class = "Date"),  Status_perc = structure(c(1L, 1L, 2L, 1L, 1L, 1L, 1L, 1L,  1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L,   2L, 3L, 3L, 3L), levels = c("<70%", "70-80%", "≥80%"), class = "factor")), row.names = c(NA, 
-27L), class = c("tbl_df", "tbl", "data.frame"))

# Create ggplot
test <- data %>% 
    ggplot( aes ( x = date, y = Percent,
                label = finalpoint , 
                colour= Percent, 
                group = 1)) +   # Note sure why, but I have to add this
    geom_link2(  ) +
  geom_point ( ) + 
  geom_text(aes(label = ifelse(is.na(finalpoint), "", sprintf("%1.1f%%",finalpoint*100))) , 
            nudge_y = +0.1, nudge_x = -50  ) +                # Add label for final point, formatted as %.
  scale_y_continuous(limits = c(0,1)) + 
  scale_colour_gradient2(low = "red", mid = "yellow" , high = "green", 
                         midpoint= 0.70,
                         limits = c(0,1)) 

test

test %>% plotly::ggplotly( ) %>%
#  tooltip =  c("Percent", "edtriage", "Num_Denom" , ")) %>%
  config(displayModeBar = F)
ulydmbyx

ulydmbyx1#

我尝试了大量不同的方法来利用ggplot。实现这个目标有一些问题。
Plotly不支持渐变线。但是,您可以沿着一条线绘制大量的点,并给予其渐变。然而,Plotly会自然地将两个轨迹与具有相同配色方案的点(Plotly中的标记)结合起来,这相当于点的大小相同。
创建和修改ggplotly对象的另一个问题是,日期轴转换为ggplot和Plotly之间的字符串数据。ggplot必须这样做,因为grid。而Plotly将日期保留为日期,因为它使用JS。
我认为最简单的方法是在这种情况下避免ggplot

沿着创建点。

这里有两个函数,一个是求qty的中点,第二个是对每个轴调用第一个函数。
然后我使用lapply循环遍历每一行和前导行,创建一个线段发送给这些函数。

queue <- function(x1, x2, qty) { # find midpoints
  # x or y axis endpoints of a line seqment, qty of points to identify
  q = list()
  q[[1]] <- c(1, qty)    # index in R starts at 1
  pts = matrix(0, qty)   # create an matrix with exactly qty positions
  pts[1] = x1; pts[qty] = x2
  while(length(q) != 0) {
    left = q[[1]][1]
    right = q[[1]][2]
    q[[1]] <- NULL # remove working segment
    center = floor((left + right)/2)         # find index midpoint
    pts[center] = (pts[left] + pts[right])/2 # assign values to specific indicies
    if(right - left > 2){
      q[[length(q) + 1]] = c(left, center)
      q[[length(q) + 1]] = c(center, right)
    }
  }
  return(pts)
}

collector <- function(x1, x2, y1, y2, qty) {
  # line segments xs and ys, qty of points to plot
  ptx = queue(x1, x2, qty)
  pty = queue(y1, y2, qty)
  return(list(ptx, pty)) # return x, y points that make up line segment
}

# convert for points along line
dt <- data$date %>% as.POSIXlt() %>% as.numeric()

newx = vector(mode = "integer")
newy = vector(mode = "double")
invisible(lapply(
  seq(1, nrow(data) - 1),
  function(j) {
    values = collector(dt[j], dt[j + 1], 
                       data$Percent[j], data$Percent[j + 1], 500)
    newx <<- append(newx, values[[1]])
    newy <<- append(newy, values[[2]])
  }
))

因为数据日期是没有时间的as.Date,所以数据和newx都需要转换成等效的时间格式。要在时间轴上有任意多的点,您需要包括时间。

#-------------- Prepare for Plotly --------------
newx3 <- newx %>% as.POSIXct(origin = "1970-01-01 UTC")
data3 <- data %>% mutate(date = as.POSIXct(date))

当您运行该代码时,它看起来像是在您的时区中。但是,当Plotly运行它时,它将以UTC运行。换句话说,日期将完全按照您最初定义的方式显示。

是时候开始谋划了。

对于第一个图,我们将使用data3。在图中,geom_point等于type = "scatter", mode = "markers"。我们将使用coloraxis,这样图中的所有数据都使用相同的配色方案。
此外,由于您将有悬停内容,我在hovertemplate中将百分比格式化为百分比。
我们将添加单个标签或annotation,而不是将您的标签称为它自己的图层(ggplot)或轨迹(plotly)。
我们将定义x轴的范围,因为我们使用了POSIX。因为我们在plot_ly的调用中设置了coloraxis,所以我们必须定义它在layout中的含义。我使用了调色板"Hot",但您可以使用任何调色板。此外,我对colorbar应用了一些设置,以便它与ggplot中的外观更接近。

fig <- plot_ly(data3, x = ~date, y = ~Percent,
        hovertemplate = "Date: %{x}<br>Percentage: %{y:.0%}<extra></extra>",
        marker = list(color = ~Percent, coloraxis = "coloraxis"),
        type = "scatter", mode = "markers") %>% 
  layout(xaxis = list(range = range(data3$date)),
         hoverdistance = -1,
         annotations = list(
           showarrow = T, x = data3[nrow(data3), ]$date, 
           y = data3[nrow(data3), ]$Percent, text = "82.44%", yshift = 1,
           xanchor = "center", yanchor = "middle", 
           ax = 20, ay = -30),
         coloraxis = list(
           colorscale = "Hot", cmid = .7,
           colorbar = list(title = "", tick0 = 0, dtick = .25,
                           outlinewidth = 0, thickness = 20,
                           len = .5)))

接下来,我们将绘制将替换直线的点。我们仍然需要分配coloraxis,但根本不需要分配layout。当我们合并这两个图时,我们将使用第一个图中的布局。
由于fig中的点是相关点,因此我已经从该图中删除了悬停数据。

fig2 <- plot_ly(x = newx3, y = newy, hoverinfo = "skip",
                type = 'scatter', mode = 'markers', showlegend = F,
                marker = list(color = ~newy, coloraxis = "coloraxis",
                             size = 2.5))

这些图需要是完整的Plotly对象,这样我们就可以从fig2中提取数据并将其放入fig中。

fig <- plotly_build(fig)
fig2 <- plotly_build(fig2)
fig$x$data <- list(fig$x$data[[1]], fig2$x$data[[1]])
fig # done!

相关问题