R plotly 分离功能性图例

6

我想通过R plotly生成一个带有独立图例的图形,同时保持颜色比例尺。

这是我目前的代码:

library(plotly)

X <- data.frame(xcoord = 1:6,
                ycoord = 1:6,
                score  = 1:6,
                gender = c("M", "M", "M", "F", "F", "F"),
                age = c("young", "old", "old", "old", "young", "young"))

plot_ly(data = X, x = ~xcoord, y = ~ycoord, split = ~interaction(age, gender),
        type = "scatter", mode = "markers",
        marker = list(color = ~score,
                      colorbar = list(len = .5, y = .3)))

这是结果:
outcome 如您所见,色条混乱且两个类别相互交织。
我需要为age(young vs old)和gender(M vs F)分别设置图例,可以独立于彼此点击。这将是预期结果:
expected outcome
编辑1
这是使用ggplot2获得的等效结果:
gg <- ggplot(X, aes(x = xcoord, y = ycoord)) +
  geom_point(aes(color = score, shape = gender, alpha = age), size = 5) +
  scale_shape_manual(values = c("M" = 19, "F" = 19)) +
  scale_alpha_manual(values = c("young" = 1, "old" = 1))

ggplotly(gg)

在ggplot中它能正确地显示,但应用ggplotly()后会出现问题。

请注意,我更倾向于使用本地的plotly图表解决方案,而不是像其他帖子中提出的事后ggplotly()修复方法。


编辑 2
尽管当前答案已经将两个图例(agegender)分开,但它们并不可操作。例如,如果您单击young级别,整个age图例将被切换打开/关闭。这里的目标是使每个图例的每个子级别可以独立地切换,通过单击图例级别,点将相应地显示/隐藏。


我尝试根据 https://plotly.com/r/colorscales/#share-color-axis 在 layout 中设置一个共同的 coloraxis;虽然这在热力图示例中有效,但是 plot_ly 抛出了一个警告,说明此属性不适用于散点[图]对象。 - user18309711
3个回答

4
Plotly似乎不容易支持此功能,因为不同的指南链接到多个数据点。例如在“年龄”跟踪上取消选择“旧”将不会从“性别”跟踪的单独一组点中删除任何内容。
这是一个解决方法,使用crosstalk和SharedData数据对象。它不是通过选择/取消选择plotly traces来实现,而是使用数据集上的过滤器来进行操作。技术上实现了所请求的选择行为,但是否是有效的解决方案取决于最终应用程序。如果该机制对您有用,则可能有方法调整样式和布局,使其更符合plotly风格。
library(crosstalk)

#SharedData object used for filters and plot
shared <- SharedData$new(X) 

crosstalk::bscols(
  widths = c(2, 10),
   list(
     crosstalk::filter_checkbox("Age", 
                                label = "Age",
                                sharedData = shared, 
                                group = ~age),
     crosstalk::filter_checkbox("Gender", 
                                label = "Gender",
                                sharedData = shared, 
                                group = ~gender)
   ),
   plot_ly(data = shared, x = ~xcoord, y = ~ycoord,
           type = "scatter", mode = "markers",
           marker = list(color = ~score,
                         colorbar = list(len = .5, y = .3),
                         cmin = 0, cmax = 6)) %>%
    layout(
      xaxis = list(range=c(.5,6.5)),
      yaxis = list(range=c(.5,6.5))
    )
   )

enter image description here

编辑:将所有复选框初始化为“已选中”

我只能通过修改输出的HTML标签来实现这一点。这会产生相同的图,但开始时所有框都被选中。

out <- crosstalk::bscols(...) #previous output object

library(htmltools)
out_tags <- htmltools::renderTags(out)

#check all Age and Gender checkboxes
out_tags$html <- stringr::str_replace_all(
  out_tags$html, 
  '(<input type="checkbox" name="(Age|Gender)" value=".*")/>',
  '\\1 checked="checked"/>'
)
out_tags$html <- HTML(out_tags$html)
# view in RStudio Viewer
browsable(as.tags(out_tags))
#or from Rmd chunk
as.tags(out_tags)

非常感谢,这确实按预期工作!您知道是否可以默认情况下将所有复选框都“选中”吗?感觉有点奇怪,当图表初始化时,没有任何框被选中,但所有数据都显示出来。此外,当每个框都未选中时,仍然会显示一些数据点的数据。 - mat
是的,有些行为感觉奇怪。我将添加一些代码来预检查所有框,但只通过修改输出HTML对象... 显然,取消选中所有内容不会触发重新渲染,因此最近选择的点仍会留在绘图上。如果纯粹的plotly之外的解决方案是可行的选项,则使用具有plotly输出的闪亮输入元素应该解决这些问题。 - pholzm

1
这并不完全符合您的要求。但我能够创建一个有意义的颜色条。
我删除了组之间的交互调用,并创建了一个单独的跟踪。然后,我创建了图例组并对其进行命名,以为genderage创建单独的图例。当我将color =从创建颜色条的调用中提取出来时,这会同步颜色比例尺。
但是,它会将颜色分配给年龄和性别标签,这是没有意义的!有一些东西与您的要求不符,但是有人可能可以在这些信息的基础上构建更多内容。
plot_ly(data = X, x = ~xcoord, y = ~ycoord, 
        split = ~age,
        legendgroup = 'age', # create first split and name it
        legendgrouptitle = list(text = "Age"),
        type = "scatter", mode = "markers",
        color = ~score,
        marker = list(colorbar = list(len = .5, y = .3))) %>% 
  add_trace(split = ~gender,
            legendgroup = 'gender', # create second split and name it
            color = ~score,
            legendgrouptitle = list(text = "Gender")) %>% 
    colorbar(title = 'Score')

enter image description here


谢谢。我们离解决方案越来越近了。主要问题是(就像上面的答案一样),我需要每个图例级别可点击。例如,我想点击“老年人”只显示/隐藏老年参与者。同样适用于“性别”。 - mat

0

我不确定这是否正是您想要的。我尝试使用两个标记创建了年龄和性别的图例。这些图例可以独立点击,但我不确定您是否希望以这种方式进行点击。您还可以点击色条。您可以使用以下代码:

library(tidyverse)
library(plotly)
plot_ly() %>%
  add_markers(data = X,
            x = ~xcoord, 
            y = ~ycoord, 
            type = "scatter", 
            mode = "markers",
            #name = "M",
            color = I("grey"),
            split = ~gender,
            legendgroup = 'gender', 
            legendgrouptitle = list(text = "Gender")) %>%
  add_markers(data = X,
              x = ~xcoord, 
              y = ~ycoord, 
              type = "scatter", 
              mode = "markers",
              #name = "M",
              color = I("grey"),
              split = ~age,
              legendgroup = 'age', 
              legendgrouptitle = list(text = "Age")) %>%
  add_trace(data = X,
            x = ~xcoord, 
            y = ~ycoord, 
            type = "scatter", 
            mode = "markers",
            name = "",
            marker = list(color = ~score,
                          colorbar = list(len = .5, y = .3)))

输出结果如下:

enter image description here


谢谢。问题是,我需要每个图例的级别可点击。例如,我想要能够单击“old”以仅显示/隐藏年龄较大的参与者。同样适用于“gender”。 - mat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接