如何在 r 中制作两个过滤器以绘图方式切换图表线条的可见性?我如何在过滤器中使用 multi-select?

How do I make two filters in r plotly toggle visibility of lines of a chart? How do I multi-select in the filters?

我正在尝试使用 R plot_ly 创建折线图,可以使用沿“产品”和“Chip_type”过滤的过滤器按钮打开和关闭折线图。 这个想法是供应商(“供应商”/“Supplier_text”)每月(“日期”)为公司的不同产品部门(“产品”)供应不同种类的芯片(“Chip_type”) .为了了解顶级供应商的概况,我想为每个供应商画一条线,图例中显示“Supplier_text”,图例条目按显示在“[”前面的 abs(number) 降序排序=67=]”。在这方面,数据 tibble 被正确排序。 “总体”条目是指该产品的所有供应商的总和。

可在 post 的末尾找到完整的数据集。

sample from dat :

    Date(chr) Supplier              Supplier_text                        order(int) Chip_type Product     n(chr)
1   2019-11   Overall Smartphones   94757 |   17.9% - Overall Smartphones     1     Micro   Smartphones    106
2   2019-11   Overall Smartphones   94757 |   17.9% - Overall Smartphones     1      Nano   Smartphones  16920
3   2019-11   Overall Smartphones   94757 |   17.9% - Overall Smartphones     1    BiMech   Smartphones  61216
4   2019-11   Overall Smartphones   94757 |   17.9% - Overall Smartphones     1     Titan   Smartphones 363698
5   2019-11   Overall Smartphones   94757 |   17.9% - Overall Smartphones     1   Quantum   Smartphones  50797
6   2019-11   Overall Smartphones   94757 |   17.9% - Overall Smartphones     1  Platinum   Smartphones  52715
7   2019-11   Overall Smartphones   94757 |   17.9% - Overall Smartphones     1 PlainChip   Smartphones 174342
8   2019-11   Overall Smartphones   94757 |   17.9% - Overall Smartphones     1   Classic   Smartphones   9319
9   2019-12   Overall Smartphones   94757 |   17.9% - Overall Smartphones     1     Micro   Smartphones     92
10  2019-12   Overall Smartphones   94757 |   17.9% - Overall Smartphones     1      Nano   Smartphones  16928
11  2019-12   Overall Smartphones   94757 |   17.9% - Overall Smartphones     1    BiMech   Smartphones  40920
17  2019-11      Overall Monitors     -33239 |  -37.8% - Overall Monitors     2     Micro      Monitors      3
18  2019-11      Overall Monitors     -33239 |  -37.8% - Overall Monitors     2      Nano      Monitors   1536
19  2019-11      Overall Monitors     -33239 |  -37.8% - Overall Monitors     2    BiMech      Monitors   6793
20  2019-11      Overall Monitors     -33239 |  -37.8% - Overall Monitors     2     Titan      Monitors  45146
21  2019-11      Overall Monitors     -33239 |  -37.8% - Overall Monitors     2   Quantum      Monitors   7922
22  2019-11      Overall Monitors     -33239 |  -37.8% - Overall Monitors     2  Platinum      Monitors   5359
23  2019-11      Overall Monitors     -33239 |  -37.8% - Overall Monitors     2 PlainChip      Monitors  27390
24  2019-11      Overall Monitors     -33239 |  -37.8% - Overall Monitors     2   Classic      Monitors   1131
25  2019-12      Overall Monitors     -33239 |  -37.8% - Overall Monitors     2     Micro      Monitors     12
33  2019-11                     A                    -17385 |  -88.0% - A     3     Titan   Smartphones   3619
34  2019-11                     A                    -17385 |  -88.0% - A     3  Platinum   Smartphones     13
35  2019-11                     A                    -17385 |  -88.0% - A     3   Quantum   Smartphones      2

为了保持顺序(稍后能够切换正确的行!)我正在循环添加跟踪到一个空的 plot_ly 对象,如下所示:

library(stringr)
library(dplyr)
library(plotly)


# "Rebuilding" the data frame as the loop runs to see if what the loop does to the traces ends up being the same (order) as the original data frame. For that, I create an empty object first:
dat_plotly_object_copy = c() 


plotly_object <- plot_ly()
id = 1

# I loop along "order", which marks all data of a single supplier:
for(id in 1:max(dat$order)){ 
  dat_one_supplier <- filter(dat, order == id)
  plotly_object <- plotly_object %>% add_trace(., data = dat_one_supplier,
# I filter the data set by supplier, to be able to create a line along the dates (~x) per supplier (~Supplier_text) and Chip_type (~n):
                                 x = ~Date,
                                 y = ~n,
                                 color = ~Supplier_text,
                                 type = "scatter",
                                 mode = "lines") 
  dat_plotly_object_copy <- dat_plotly_object_copy %>% 
    rbind(.,dat_one_supplier)
}

identical(dat, dat_plotly_object_copy)
# The created data frame seems to be identical to what the loop does - so the order should match (?)

使用此代码设置图例...

Parts_legend <- list(
  font = list(
    family = "sans-serif",
    size = 12,
    color = "#000"),
  title = list(text="<b> Delta previous month by Supplier - Absolute </b>"),
  bgcolor = "#E2E2E2",
  bordercolor = "#FFFFFF",
  borderwidth = 2,
  layout.legend = "constant",
  traceorder = "grouped")

..并显示对象:

plotly_object %>% 
  layout(legend = Parts_legend,
         title = "by supplier delta previous month",
         xaxis = list(title = 'Date'),
         yaxis = list(title = 'Chip Volume'))

给我留下了下面的图表,这似乎是正确的:供应商是通过名称前面的 abs(数字)输入的! [1]: https://i.stack.imgur.com/bDTWZ.png

现在我需要添加按钮。在第一步中,我创建了两个数据框,用于指示一条线稍后是否可见 (TRUE) 或不可见 (FALSE)。 我试图以与 dat 相同的格式创建它们 - 这样我就可以为 dat/过滤变量可以采用的值的每一行得到一个 TRUE 或 FALSE:

Parts_product_filter <- select(dat,Supplier_text,order,Product,Chip_type) %>% 
  mutate(Smartphones = ifelse(Product == "Smartphones",T,F) %>% sapply(.,list), 
         TVs = ifelse(Product == "TVs",T,F) %>% sapply(.,list),
         Monitors = ifelse(Product == "Monitors",T,F) %>% sapply(.,list),
         Miscellaneous = ifelse(Product == "Miscellaneous",T,F) %>% sapply(.,list))


Parts_chip_type_filter <- select(dat,Supplier_text,order,Product,Chip_type) %>% 
  mutate(Micro = ifelse(Chip_type == "Micro",T,F) %>% sapply(.,list),
         Nano = ifelse(Chip_type == "Nano",T,F) %>% sapply(.,list),
         BiMech = ifelse(Chip_type == "BiMech",T,F) %>% sapply(.,list),
         Titan = ifelse(Chip_type == "Titan",T,F) %>% sapply(.,list),
         Quantum = ifelse(Chip_type == "Quantum",T,F) %>% sapply(.,list),
         Platinum = ifelse(Chip_type == "Platinum",T,F) %>% sapply(.,list),
         PlainChip = ifelse(Chip_type == "PlainChip",T,F) %>% sapply(.,list),
         Classic = ifelse(Chip_type == "Classic",T,F) %>% sapply(.,list))

将按钮添加到 plotly_object,我尝试设置它们,以便它们根据上面创建的“_filter”数据框的各个列进行过滤:

plotly_object %>% 
  layout(legend = Parts_legend,
         title = "by supplier delta previous month",
         xaxis = list(title = 'Date'),
         yaxis = list(title = 'Chip Volume'),
         updatemenus = list(
           list(
             active = 0,
             type = "dropdown",
             y = 1.1,
             direction = "right",

# See from here:
             buttons = list(
               
               list(label = "All",
                    method = "restyle",
                    args = list("visible",T)),
               
               list(label = "Smartphones",
                    method = "restyle",
                    args = list("visible",Parts_product_filter$Smartphones)),
               
               list(label = "TVs",
                    method = "restyle",
                    args = list("visible",Parts_product_filter$TVs)),
               
               list(label = "Monitors",
                    method = "restyle",
                    args = list("visible",Parts_product_filter$Monitors)),
               
               list(label = "Miscellaneous",
                    method = "restyle",
                    args = list("visible",Parts_product_filter$Miscellaneous))
             )
           ),
           list(
             active = 0,
             type = "dropdown",
             y = 1.03,
             direction = "right",
             buttons = list(
               
               list(label = "All",
                    method = "restyle",
                    args = list("visible",T)),
               
               list(label = "Micro",
                    method = "restyle",
                    args = list("visible",Parts_chip_type_filter$Micro)),
               
               list(label = "Nano",
                    method = "restyle",
                    args = list("visible",Parts_chip_type_filter$Nano)),
               
               list(label = "BiMech",
                    method = "restyle",
                    args = list("visible",Parts_chip_type_filter$BiMech)),
               
               list(label = "Titan",
                    method = "restyle",
                    args = list("visible",Parts_chip_type_filter$Titan)),
               
               list(label = "Quantum",
                    method = "restyle",
                    args = list("visible",Parts_chip_type_filter$Quantum)),
               
               list(label = "Platinum",
                    method = "restyle",
                    args = list("visible",Parts_chip_type_filter$Platinum)),
               
               list(label = "PlainChip",
                    method = "restyle",
                    args = list("visible",Parts_chip_type_filter$PlainChip)),
               
               list(label = "Classic",
                    method = "restyle",
                    args = list("visible",Parts_chip_type_filter$Classic))
             )
             
           )
         )
  )

而这根本行不通。我一定是过滤器设置错误。我知道,因为当我过滤“Product = TVs”和“Chip_type = Nano”的组合时,没有出现线条....

https://i.stack.imgur.com/MaJ5r.png

...虽然有数据:

> dat %>% filter(Product == "TVs") %>% filter(Chip_type == "Nano")
# A tibble: 8 x 7
  Date    Supplier    Supplier_text                 order Chip_type Product n    
  <chr>   <chr>       <chr>                         <int> <chr>    <chr>   <chr>
1 2019-11 Overall TVs 14373 |    6.0% - Overall TVs     4 Nano     TVs     4643 
2 2019-12 Overall TVs 14373 |    6.0% - Overall TVs     4 Nano     TVs     6904 
3 2019-11 J           2603 |    5.8% - J               13 Nano     TVs     3    
4 2019-12 J           2603 |    5.8% - J               13 Nano     TVs     3    
5 2019-11 M           -1711 |  -19.4% - M              16 Nano     TVs     2    
6 2019-12 M           -1711 |  -19.4% - M              16 Nano     TVs     1    
7 2019-11 O           1315 |   23.6% - O               19 Nano     TVs     2    
8 2019-12 O           1315 |   23.6% - O               19 Nano     TVs     1 

我真的很期待你的建议如何正确设置按钮的可见性切换!

我知道有两个相似的post,但是关注的是多张图。很可能是我技术不够,但我无法通过提供的解决方案解决我的问题,非常感谢您的考虑和帮助!

在 Python(不是 R)中完成的类似内容,但使用一个过滤器:

后续将是:是否可以select多个类别,i。 e. “Nano”和“Classic”,可能同时来自另一个过滤器的“智能手机”和“电视”? 这是 Python 的 post,但不幸的是没有答案: Selecting multiple buttons at once in a plotly graph

在此先感谢您!

要导入的完整数据集:

<!-- begin snippet: js hide: true -->
dat <- structure(list(Date = c("2019-11", "2019-11", "2019-11", "2019-11", 
"2019-11", "2019-11", "2019-11", "2019-11", "2019-12", "2019-12", 
"2019-12", "2019-12", "2019-12", "2019-12", "2019-12", "2019-12", 
"2019-11", "2019-11", "2019-11", "2019-11", "2019-11", "2019-11", 
"2019-11", "2019-11", "2019-12", "2019-12", "2019-12", "2019-12", 
"2019-12", "2019-12", "2019-12", "2019-12", "2019-11", "2019-11", 
"2019-11", "2019-11", "2019-12", "2019-12", "2019-12", "2019-12", 
"2019-11", "2019-11", "2019-11", "2019-11", "2019-11", "2019-11", 
"2019-11", "2019-11", "2019-12", "2019-12", "2019-12", "2019-12", 
"2019-12", "2019-12", "2019-12", "2019-12", "2019-11", "2019-11", 
"2019-11", "2019-11", "2019-12", "2019-12", "2019-12", "2019-12", 
"2019-12", "2019-11", "2019-11", "2019-11", "2019-11", "2019-11", 
"2019-12", "2019-12", "2019-12", "2019-12", "2019-11", "2019-11", 
"2019-11", "2019-11", "2019-11", "2019-12", "2019-12", "2019-12", 
"2019-12", "2019-12", "2019-11", "2019-11", "2019-11", "2019-11", 
"2019-11", "2019-12", "2019-12", "2019-12", "2019-12", "2019-12", 
"2019-12", "2019-11", "2019-11", "2019-12", "2019-12", "2019-11", 
"2019-12", "2019-12", "2019-11", "2019-11", "2019-11", "2019-12", 
"2019-12", "2019-11", "2019-12", "2019-12", "2019-12", "2019-12", 
"2019-11", "2019-11", "2019-12", "2019-12", "2019-11", "2019-11", 
"2019-11", "2019-12", "2019-12", "2019-11", "2019-11", "2019-11", 
"2019-12", "2019-12", "2019-12", "2019-11", "2019-11", "2019-12", 
"2019-12", "2019-12", "2019-12", "2019-11", "2019-11", "2019-11", 
"2019-11", "2019-11", "2019-11", "2019-11", "2019-12", "2019-12", 
"2019-12", "2019-12", "2019-12", "2019-12", "2019-12", "2019-12", 
"2019-11", "2019-11", "2019-12", "2019-12", "2019-12", "2019-12", 
"2019-12", "2019-11", "2019-11", "2019-11", "2019-11", "2019-12", 
"2019-12", "2019-11", "2019-11", "2019-11", "2019-11", "2019-12", 
"2019-12", "2019-12", "2019-12", "2019-11", "2019-11", "2019-11", 
"2019-12", "2019-12", "2019-12", "2019-11", "2019-12", "2019-12", 
"2019-11", "2019-11", "2019-12", "2019-12"), Supplier = c("Overall Smartphones", 
"Overall Smartphones", "Overall Smartphones", "Overall Smartphones", 
"Overall Smartphones", "Overall Smartphones", "Overall Smartphones", 
"Overall Smartphones", "Overall Smartphones", "Overall Smartphones", 
"Overall Smartphones", "Overall Smartphones", "Overall Smartphones", 
"Overall Smartphones", "Overall Smartphones", "Overall Smartphones", 
"Overall Monitors", "Overall Monitors", "Overall Monitors", "Overall Monitors", 
"Overall Monitors", "Overall Monitors", "Overall Monitors", "Overall Monitors", 
"Overall Monitors", "Overall Monitors", "Overall Monitors", "Overall Monitors", 
"Overall Monitors", "Overall Monitors", "Overall Monitors", "Overall Monitors", 
"A", "A", "A", "A", "A", "A", "A", "A", "Overall TVs", "Overall TVs", 
"Overall TVs", "Overall TVs", "Overall TVs", "Overall TVs", "Overall TVs", 
"Overall TVs", "Overall TVs", "Overall TVs", "Overall TVs", "Overall TVs", 
"Overall TVs", "Overall TVs", "Overall TVs", "Overall TVs", "B", 
"B", "B", "B", "B", "B", "B", "B", "B", "C", "C", "C", "C", "C", 
"C", "C", "C", "C", "D", "D", "D", "D", "D", "D", "D", "D", "D", 
"D", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "F", 
"F", "F", "F", "G", "G", "G", "H", "H", "H", "H", "H", "I", "I", 
"I", "I", "I", "J", "J", "J", "J", "K", "K", "K", "K", "K", "L", 
"L", "L", "L", "L", "L", "M", "M", "M", "M", "M", "M", "Overall Miscellaneous", 
"Overall Miscellaneous", "Overall Miscellaneous", "Overall Miscellaneous", 
"Overall Miscellaneous", "Overall Miscellaneous", "Overall Miscellaneous", 
"Overall Miscellaneous", "Overall Miscellaneous", "Overall Miscellaneous", 
"Overall Miscellaneous", "Overall Miscellaneous", "Overall Miscellaneous", 
"Overall Miscellaneous", "Overall Miscellaneous", "N", "N", "N", 
"N", "N", "N", "N", "O", "O", "O", "O", "O", "O", "P", "P", "P", 
"P", "P", "P", "P", "P", "C", "C", "C", "C", "C", "C", "Q", "Q", 
"Q", "R", "R", "R", "S"), Supplier_text = c("94757 |   17.9% - Overall Smartphones", 
"94757 |   17.9% - Overall Smartphones", "94757 |   17.9% - Overall Smartphones", 
"94757 |   17.9% - Overall Smartphones", "94757 |   17.9% - Overall Smartphones", 
"94757 |   17.9% - Overall Smartphones", "94757 |   17.9% - Overall Smartphones", 
"94757 |   17.9% - Overall Smartphones", "94757 |   17.9% - Overall Smartphones", 
"94757 |   17.9% - Overall Smartphones", "94757 |   17.9% - Overall Smartphones", 
"94757 |   17.9% - Overall Smartphones", "94757 |   17.9% - Overall Smartphones", 
"94757 |   17.9% - Overall Smartphones", "94757 |   17.9% - Overall Smartphones", 
"94757 |   17.9% - Overall Smartphones", "-33239 |  -37.8% - Overall Monitors", 
"-33239 |  -37.8% - Overall Monitors", "-33239 |  -37.8% - Overall Monitors", 
"-33239 |  -37.8% - Overall Monitors", "-33239 |  -37.8% - Overall Monitors", 
"-33239 |  -37.8% - Overall Monitors", "-33239 |  -37.8% - Overall Monitors", 
"-33239 |  -37.8% - Overall Monitors", "-33239 |  -37.8% - Overall Monitors", 
"-33239 |  -37.8% - Overall Monitors", "-33239 |  -37.8% - Overall Monitors", 
"-33239 |  -37.8% - Overall Monitors", "-33239 |  -37.8% - Overall Monitors", 
"-33239 |  -37.8% - Overall Monitors", "-33239 |  -37.8% - Overall Monitors", 
"-33239 |  -37.8% - Overall Monitors", "-17385 |  -88.0% - A", 
"-17385 |  -88.0% - A", "-17385 |  -88.0% - A", "-17385 |  -88.0% - A", 
"-17385 |  -88.0% - A", "-17385 |  -88.0% - A", "-17385 |  -88.0% - A", 
"-17385 |  -88.0% - A", "14373 |    6.0% - Overall TVs", "14373 |    6.0% - Overall TVs", 
"14373 |    6.0% - Overall TVs", "14373 |    6.0% - Overall TVs", 
"14373 |    6.0% - Overall TVs", "14373 |    6.0% - Overall TVs", 
"14373 |    6.0% - Overall TVs", "14373 |    6.0% - Overall TVs", 
"14373 |    6.0% - Overall TVs", "14373 |    6.0% - Overall TVs", 
"14373 |    6.0% - Overall TVs", "14373 |    6.0% - Overall TVs", 
"14373 |    6.0% - Overall TVs", "14373 |    6.0% - Overall TVs", 
"14373 |    6.0% - Overall TVs", "14373 |    6.0% - Overall TVs", 
"-8387 |  -80.6% - B", "-8387 |  -80.6% - B", "-8387 |  -80.6% - B", 
"-8387 |  -80.6% - B", "-8387 |  -80.6% - B", "-8387 |  -80.6% - B", 
"-8387 |  -80.6% - B", "-8387 |  -80.6% - B", "-8387 |  -80.6% - B", 
"5701 |   79.2% - C", "5701 |   79.2% - C", "5701 |   79.2% - C", 
"5701 |   79.2% - C", "5701 |   79.2% - C", "5701 |   79.2% - C", 
"5701 |   79.2% - C", "5701 |   79.2% - C", "5701 |   79.2% - C", 
"5155 |   49.2% - D", "5155 |   49.2% - D", "5155 |   49.2% - D", 
"5155 |   49.2% - D", "5155 |   49.2% - D", "5155 |   49.2% - D", 
"5155 |   49.2% - D", "5155 |   49.2% - D", "5155 |   49.2% - D", 
"5155 |   49.2% - D", "4977 |   95.4% - E", "4977 |   95.4% - E", 
"4977 |   95.4% - E", "4977 |   95.4% - E", "4977 |   95.4% - E", 
"4977 |   95.4% - E", "4977 |   95.4% - E", "4977 |   95.4% - E", 
"4977 |   95.4% - E", "4977 |   95.4% - E", "4977 |   95.4% - E", 
"3676 |18380.0% - F", "3676 |18380.0% - F", "3676 |18380.0% - F", 
"3676 |18380.0% - F", "-3132 |  -99.4% - G", "-3132 |  -99.4% - G", 
"-3132 |  -99.4% - G", "3065 |   33.6% - H", "3065 |   33.6% - H", 
"3065 |   33.6% - H", "3065 |   33.6% - H", "3065 |   33.6% - H", 
"-2854 |  -56.1% - I", "-2854 |  -56.1% - I", "-2854 |  -56.1% - I", 
"-2854 |  -56.1% - I", "-2854 |  -56.1% - I", "2603 |    5.8% - J", 
"2603 |    5.8% - J", "2603 |    5.8% - J", "2603 |    5.8% - J", 
"2564 |   39.4% - K", "2564 |   39.4% - K", "2564 |   39.4% - K", 
"2564 |   39.4% - K", "2564 |   39.4% - K", "1843 |  334.5% - L", 
"1843 |  334.5% - L", "1843 |  334.5% - L", "1843 |  334.5% - L", 
"1843 |  334.5% - L", "1843 |  334.5% - L", "-1711 |  -19.4% - M", 
"-1711 |  -19.4% - M", "-1711 |  -19.4% - M", "-1711 |  -19.4% - M", 
"-1711 |  -19.4% - M", "-1711 |  -19.4% - M", "-1662 |  -30.0% - Overall Miscellaneous", 
"-1662 |  -30.0% - Overall Miscellaneous", "-1662 |  -30.0% - Overall Miscellaneous", 
"-1662 |  -30.0% - Overall Miscellaneous", "-1662 |  -30.0% - Overall Miscellaneous", 
"-1662 |  -30.0% - Overall Miscellaneous", "-1662 |  -30.0% - Overall Miscellaneous", 
"-1662 |  -30.0% - Overall Miscellaneous", "-1662 |  -30.0% - Overall Miscellaneous", 
"-1662 |  -30.0% - Overall Miscellaneous", "-1662 |  -30.0% - Overall Miscellaneous", 
"-1662 |  -30.0% - Overall Miscellaneous", "-1662 |  -30.0% - Overall Miscellaneous", 
"-1662 |  -30.0% - Overall Miscellaneous", "-1662 |  -30.0% - Overall Miscellaneous", 
"-1439 |  -95.6% - N", "-1439 |  -95.6% - N", "-1439 |  -95.6% - N", 
"-1439 |  -95.6% - N", "-1439 |  -95.6% - N", "-1439 |  -95.6% - N", 
"-1439 |  -95.6% - N", "1315 |   23.6% - O", "1315 |   23.6% - O", 
"1315 |   23.6% - O", "1315 |   23.6% - O", "1315 |   23.6% - O", 
"1315 |   23.6% - O", "193 |  232.5% - P", "193 |  232.5% - P", 
"193 |  232.5% - P", "193 |  232.5% - P", "193 |  232.5% - P", 
"193 |  232.5% - P", "193 |  232.5% - P", "193 |  232.5% - P", 
"-152 |  -38.1% - C", "-152 |  -38.1% - C", "-152 |  -38.1% - C", 
"-152 |  -38.1% - C", "-152 |  -38.1% - C", "-152 |  -38.1% - C", 
"-98 |  -79.7% - Q", "-98 |  -79.7% - Q", "-98 |  -79.7% - Q", 
"92 | 3066.7% - R", "92 | 3066.7% - R", "92 | 3066.7% - R", "-70 |  -90.9% - S"
), order = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 
4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, 5L, 
5L, 5L, 5L, 5L, 5L, 5L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 7L, 
7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 
8L, 8L, 8L, 8L, 9L, 9L, 9L, 9L, 10L, 10L, 10L, 11L, 11L, 11L, 
11L, 11L, 12L, 12L, 12L, 12L, 12L, 13L, 13L, 13L, 13L, 14L, 14L, 
14L, 14L, 14L, 15L, 15L, 15L, 15L, 15L, 15L, 16L, 16L, 16L, 16L, 
16L, 16L, 17L, 17L, 17L, 17L, 17L, 17L, 17L, 17L, 17L, 17L, 17L, 
17L, 17L, 17L, 17L, 18L, 18L, 18L, 18L, 18L, 18L, 18L, 19L, 19L, 
19L, 19L, 19L, 19L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 20L, 21L, 
21L, 21L, 21L, 21L, 21L, 22L, 22L, 22L, 23L, 23L, 23L, 24L), 
    Chip_type = c("Micro", "Nano", "BiMech", "Titan", "Quantum", 
    "Platinum", "PlainChip", "Classic", "Micro", "Nano", "BiMech", 
    "Titan", "Quantum", "Platinum", "PlainChip", "Classic", "Micro", 
    "Nano", "BiMech", "Titan", "Quantum", "Platinum", "PlainChip", 
    "Classic", "Micro", "Nano", "BiMech", "Titan", "Quantum", 
    "Platinum", "PlainChip", "Classic", "Titan", "Platinum", 
    "Quantum", "Nano", "Titan", "Platinum", "Nano", "PlainChip", 
    "Micro", "Nano", "BiMech", "Titan", "Quantum", "Platinum", 
    "PlainChip", "Classic", "Micro", "Nano", "BiMech", "Titan", 
    "Quantum", "Platinum", "PlainChip", "Classic", "Titan", "Platinum", 
    "Quantum", "Nano", "Titan", "Nano", "Quantum", "Platinum", 
    "PlainChip", "PlainChip", "Platinum", "Nano", "Quantum", 
    "Classic", "PlainChip", "Platinum", "Nano", "Quantum", "PlainChip", 
    "Platinum", "Quantum", "Nano", "Classic", "PlainChip", "Nano", 
    "Platinum", "Quantum", "Classic", "PlainChip", "Quantum", 
    "Platinum", "Classic", "Nano", "PlainChip", "Quantum", "Platinum", 
    "Nano", "Classic", "BiMech", "Titan", "Nano", "Titan", "Quantum", 
    "Titan", "Titan", "Platinum", "PlainChip", "Nano", "Classic", 
    "PlainChip", "Nano", "PlainChip", "PlainChip", "Quantum", 
    "Nano", "Classic", "Titan", "Nano", "Titan", "Nano", "Platinum", 
    "PlainChip", "Quantum", "Platinum", "PlainChip", "Titan", 
    "PlainChip", "Platinum", "Titan", "PlainChip", "Platinum", 
    "Titan", "Nano", "Titan", "Platinum", "Nano", "PlainChip", 
    "Nano", "BiMech", "Titan", "Quantum", "Platinum", "PlainChip", 
    "Classic", "Micro", "Nano", "BiMech", "Titan", "Quantum", 
    "Platinum", "PlainChip", "Classic", "Titan", "Quantum", "Titan", 
    "Nano", "Quantum", "Platinum", "PlainChip", "Titan", "Quantum", 
    "Nano", "Micro", "Titan", "Nano", "Platinum", "Quantum", 
    "Nano", "Classic", "Quantum", "Platinum", "Nano", "Classic", 
    "Classic", "Quantum", "Nano", "Classic", "Quantum", "Nano", 
    "Quantum", "Quantum", "Nano", "Quantum", "Nano", "Quantum", 
    "Titan"), Product = c("Smartphones", "Smartphones", "Smartphones", 
    "Smartphones", "Smartphones", "Smartphones", "Smartphones", 
    "Smartphones", "Smartphones", "Smartphones", "Smartphones", 
    "Smartphones", "Smartphones", "Smartphones", "Smartphones", 
    "Smartphones", "Monitors", "Monitors", "Monitors", "Monitors", 
    "Monitors", "Monitors", "Monitors", "Monitors", "Monitors", 
    "Monitors", "Monitors", "Monitors", "Monitors", "Monitors", 
    "Monitors", "Monitors", "Smartphones", "Smartphones", "Smartphones", 
    "Smartphones", "Smartphones", "Smartphones", "Smartphones", 
    "Smartphones", "TVs", "TVs", "TVs", "TVs", "TVs", "TVs", 
    "TVs", "TVs", "TVs", "TVs", "TVs", "TVs", "TVs", "TVs", "TVs", 
    "TVs", "Monitors", "Monitors", "Monitors", "Monitors", "Monitors", 
    "Monitors", "Monitors", "Monitors", "Monitors", "Smartphones", 
    "Smartphones", "Smartphones", "Smartphones", "Smartphones", 
    "Smartphones", "Smartphones", "Smartphones", "Smartphones", 
    "Smartphones", "Smartphones", "Smartphones", "Smartphones", 
    "Smartphones", "Smartphones", "Smartphones", "Smartphones", 
    "Smartphones", "Smartphones", "Smartphones", "Smartphones", 
    "Smartphones", "Smartphones", "Smartphones", "Smartphones", 
    "Smartphones", "Smartphones", "Smartphones", "Smartphones", 
    "Smartphones", "Monitors", "Monitors", "Monitors", "Monitors", 
    "Monitors", "Monitors", "Monitors", "Monitors", "Monitors", 
    "Monitors", "Monitors", "Monitors", "Monitors", "Monitors", 
    "Monitors", "Monitors", "Monitors", "TVs", "TVs", "TVs", 
    "TVs", "Smartphones", "Smartphones", "Smartphones", "Smartphones", 
    "Smartphones", "TVs", "TVs", "TVs", "TVs", "TVs", "TVs", 
    "TVs", "TVs", "TVs", "TVs", "TVs", "TVs", "Miscellaneous", 
    "Miscellaneous", "Miscellaneous", "Miscellaneous", "Miscellaneous", 
    "Miscellaneous", "Miscellaneous", "Miscellaneous", "Miscellaneous", 
    "Miscellaneous", "Miscellaneous", "Miscellaneous", "Miscellaneous", 
    "Miscellaneous", "Miscellaneous", "Monitors", "Monitors", 
    "Monitors", "Monitors", "Monitors", "Monitors", "Monitors", 
    "TVs", "TVs", "TVs", "TVs", "TVs", "TVs", "Miscellaneous", 
    "Miscellaneous", "Miscellaneous", "Miscellaneous", "Miscellaneous", 
    "Miscellaneous", "Miscellaneous", "Miscellaneous", "Miscellaneous", 
    "Miscellaneous", "Miscellaneous", "Miscellaneous", "Miscellaneous", 
    "Miscellaneous", "Miscellaneous", "Miscellaneous", "Miscellaneous", 
    "Miscellaneous", "Miscellaneous", "Miscellaneous", "Miscellaneous"
    ), n = c("106", "16920", "61216", "363698", "50797", "52715", 
    "174342", "9319", "92", "16928", "40920", "270963", "48605", 
    "34068", "114333", "4024", "3", "1536", "6793", "45146", 
    "7922", "5359", "27390", "1131", "12", "1311", "5431", "48107", 
    "6230", "5133", "21161", "505", "3619", "13", "2", "1", "19720", 
    "13", "10", "4", "96", "4643", "14534", "166664", "17178", 
    "17489", "30048", "5010", "96", "6904", "10463", "158060", 
    "15864", "20149", "24173", "2390", "12102", "7", "2", "1", 
    "10390", "5", "4", "2", "1", "11036", "329", "224", "2", 
    "2", "6936", "176", "85", "1", "15335", "55", "53", "48", 
    "14", "10292", "86", "47", "32", "11", "6559", "667", "631", 
    "419", "416", "4416", "336", "285", "105", "74", "2", "18", 
    "2", "18", "2", "86", "3151", "1", "14682", "77", "10", "9098", 
    "26", "2833", "5083", "2", "1", "1", "41051", "3", "45233", 
    "3", "10763", "44", "2", "6508", "2", "370", "265", "6", 
    "461", "86", "4", "5996", "2", "8826", "2", "1", "1", "503", 
    "5", "79", "3348", "742", "199", "989", "1", "473", "11", 
    "152", "3681", "363", "54", "804", "1702", "1", "1500", "2", 
    "1", "1", "1", "4868", "5", "2", "1", "5573", "1", "312", 
    "113", "3", "3", "42", "30", "6", "5", "371", "53", "19", 
    "312", "64", "23", "97", "121", "2", "3", "1", "3", "77")), row.names = c(NA, 
-182L), class = c("tbl_df", "tbl", "data.frame"))

#[1]: https://i.stack.imgur.com/bDTWZ.png #[2]: https://i.stack.imgur.com/MaJ5r.png

您创建了一个包含 182 个 T 或 F 的列表,但您真正需要的是一个包含 24 个 T 或 F 的列表,因为有 24 行、24 组、24 条迹线plotly 是要显示还是不显示。

首先,您很好地按数据中的字段对绘图进行了分组。我有第一个情节的另一种变体 - 一次调用 plot_ly 并且仍然创建所有 24 条轨迹,就像你的循环一样。

首先我做了 Supplier_text 和排序因子,这样我就可以控制图例的顺序。

# this will keep the legend order in order
d2 <- dat %>%
  mutate(Supplier_text = ordered(Supplier_text, 
                                 levels = rev(unique(dat$Supplier_text))))

然后我创建了 24 条轨迹。

(plt <- plot_ly(data = d2,
                x = ~Date,
                y = ~n,
                color = ~Supplier_text,
                type = "scatter",
                mode = "lines"))

然后我更改了您为产品创建的过滤器。你有 24 条轨迹,现在你有 24 个 T 或 F 用于此过滤器。

# changed this so it is one for each trace, not one for each row
Parts_product_filter <- d2 %>% select(Supplier_text, Product) %>%  
  mutate(Smartphones = ifelse(Product == "Smartphones",T,F) %>% sapply(.,list), 
         TVs = ifelse(Product == "TVs",T, F) %>% sapply(.,list),
         Monitors = ifelse(Product == "Monitors",T,F) %>% sapply(.,list),
         Miscellaneous = ifelse(Product == "Miscellaneous",T,F) %>% sapply(.,list)) %>% 
  unique()

你的代码的其他部分保持不变,除了 plotly_object 的对象名称,现在 plt 在连接绘图的任何调用中(两个布局和 Chip_type过滤器)。


更新替换

这仅包括“两者”按钮。

我在评论中回答你的问题,发现有些痕迹不对劲。所以当我解决这个问题时,我还添加了悬停,这样你就可以想象为什么会出现垂直线。请记住,n 是一个因素。 Plotly 不知道您要将哪个 n 值与右侧的哪个值连接,而不是通过 color.

当您将 n 设为数字字段时,plotly 会将这些值相加(除非您提供 plotly 其他划分内容的方式)。可悲的是,计算机无法读懂思想......但是......

我添加了一个 hovertemplate。如果您在图例中看到情节中没有的内容,那是 plotly 不知道该怎么做。如果将鼠标悬停在图上,您甚至可能会得到一个值,但没有线。我在最后有一些例子。

d2 <- dat %>%
  mutate(Supplier_text = ordered(Supplier_text, 
                                 levels = rev(unique(dat$Supplier_text))),
         Product = ordered(Product,
                           levels = sort(unique(dat$Product))),
         Chip_type = ordered(Chip_type, 
                             levels = sort(unique(dat$Chip_type))),
         n = as.numeric(dat$n) %>% sort(decreasing = T) %>%
           as.character() %>% ordered(., levels = unique(.))) %>% 
  arrange(n)

所有痕迹:

#------------- base plot ----------------
(plt <- d2 %>% 
    plot_ly(x = ~Date,
            y = ~n,
            color = ~Supplier_text,
            type = 'scatter',
            mode = 'lines',
            text = ~Product,
            hovertext = ~Chip_type,
            visible = T
))

我意识到当我计算痕迹时,当绘图呈现时,我没有得到 45 条痕迹,我得到了更多!只有基本图有 24 条迹线。底座和组合键都有127条轨迹。

这就是我想出并验证更正的方式。

#------------- trace count ----------------
# I used length(plt$x$attrs) to confirm the number of traces
       # -- that was a mistake!
# collect data, since it's not in the plotly object (errr)
pj = plotly_json(plt)

# read the JSON back
pjj = jsonlite::fromJSON(pj$x$data)

# number of traces:
nrow(pjj$data)
# [1] 24  # one trace for each color

组合痕迹:

#------------- add combination traces ----------------
# each of the possible button groups when both filters are opted
cmb = expand.grid(Product = levels(d2$Product), 
                  Chip_type = levels(d2$Chip_type))    
# create combo traces
invisible(
  lapply(1:nrow(cmb),  # filter for both
         function(x){
           d3 = d2 %>% filter(Product == cmb[x, 1] %>% toString(),
                              Chip_type == cmb[x, 2] %>% toString()) %>% 
             droplevels
           if(nrow(d3) < 1) {
             print(cmb[x, ]) # let me know what was skipped
             return()        # if no rows, don't make the trace
           } # end if 
           plt <<- plt %>% 
             add_trace(inherit = F,
                       data = d2 %>%
                         filter(Product == cmb[x, 1] %>% toString(),
                                Chip_type == cmb[x, 2] %>% toString()),
                       x = ~Date, y = ~n,
                       color = ~Supplier_text,
                       type = 'scatter',
                       mode = 'lines',
                       text = ~Product,
                       hovertext = ~Chip_type,
                       hovertemplate = paste0("Products: %{text}",
                                              "\nChips: %{hovertext}"),
                       visible = F #,
                       #inherit = F
             )
         })
)
cmb # validate

现在查看痕迹数:

#------------- combination traces updated trace count ----------------
# collect count
pj = plotly_json(plt)

# read the JSON back
pjj = jsonlite::fromJSON(pj$x$data)

# number of traces:
nrow(pjj$data)
# [1] 127  # whoa!

根据痕迹创建数据以确保 T/F 是正确的

#------------- trace data frame ----------------
# create data frame of the JSON content so that traces can be match with combos
plt.df = data.frame(nm = pjj$data$name, # this is Supplier_text
                    # valCount is the number of observations in the trace
                    valCount = unlist(map(pjj$data$x, ~length(.x))), 
                    # whether it's visible (is it all or not?)
                    vis = pjj$data$visible)
# inspect what you expect
tail(plt.df)

按钮组合部分

#------------- set up for button for combos ----------------
tracs = d2 %>% 
  group_by(Product, Chip_type, Supplier_text) %>%
  summarise(ct = n(), .groups = "drop") %>% 
  mutate(traces = 25:127)

# is the order the same in the plot?
tail(tracs, 10)

tail(plt.df, 10) # definitely not!

# check?
tracs %>% arrange(Chip_type) %>% tail(10)
     # that's the right order

# update tracs' order
tracs <- tracs %>% arrange(Chip_type) %>% 
  mutate(traces = 25:nrow(plt.df)) # fix trace assignment

# double-check!
plt.df[25:35,]
tracs[1:11,]
# they aren't the same, but plotting groups are

# adjust cmb to be ordered before id trace to group combos
cmb <- cmb %>% arrange(Chip_type)

现在数据已对齐 (order-wise),我们需要准确找到哪些轨迹与哪些组相关。组中的每种颜色都会有一条轨迹(即,如果 Misc Titan 在 3 种不同颜色中有 5 进/5 出,则 Misc Titan 将有三个轨迹。

#--------------- collect group to trace number ----------------
# between cmb, d2, and the traces, the three vars - product, chip, and 
# supplier text are ordered factors so the order will be the same
cmbo = invisible(
  lapply(1:nrow(cmb),
         function(x){
           rs = tracs %>% filter(Product == cmb[x, 1] %>% toString(),
                                 Chip_type == cmb[x, 2] %>% toString()) %>% 
             select(traces) %>% unlist() %>% unique(use.names = F)
           list(traces = rs)
           }) %>% setNames(paste0(cmb[, 1], " ", cmb[, 2])) # add the names
)# 32 start and stop points for the 103 traces

# check
cmbo[1:6]

现在按钮布局代码可以写成:

#---------------------- the button ----------------------
# now for the buttons...finally
# create the empty 
raw_v <- rep(F, nrow(plt.df))

cButton <- 
  lapply(1:length(cmbo),
         function(x){
           traces <- cmbo[[x]][[1]] %>% unlist()
           raw_v[traces] <- T
           as.list(unlist(raw_v))
         }) %>% setNames(names(cmbo))
# validate
length(cButton[[1]])
# [1] 127 
length(cButton)
# [1] 32 

# looks good
cmbBtn2 = lapply(1:length(cButton),
                 function(x){
                   label = names(cButton)[x] %>% gsub("\.", " ", x = .)
                   method = "restyle"
                   args = list("visible", cButton[[x]])
                   list(label = label, method = method, args = args)
                 })

按钮的all部分

#------------- set up button for "all" ----------------
all = list(list(label = "All",
                method = "restyle",
                args = list("visible",
                            as.list(unlist(
                              c(rep(T, 24), 
                                rep(F, nrow(plt.df) - 24)
                                )))) # end args
                )) # end list list

现在把它们放在一起:

#---------------------- the layout ----------------------
Parts_legend <- list(
  font = list(
    family = "sans-serif",
    size = 12,
    color = "#000"),
  title = list(text="<b> Delta previous month by Supplier - Absolute </b>"),
  bgcolor = "#E2E2E2",
  bordercolor = "#FFFFFF",
  borderwidth = 2,
  layout.legend = "constant",
  traceorder = "grouped")


plt %>% 
  layout(legend = Parts_legend,
         title = "by supplier delta previous month",
         xaxis = list(title = 'Date'),
         yaxis = list(title = 'Chip Volume'),
         margin = list(l = 120, t = 100),
         updatemenus = list(
           list(
             active = 0,
             type = "dropdown",
             y = 1.2,
             direction = "down",
             buttons = append(all, cmbBtn2)))
  ) # end layout

一些检查:

# check some of these for accuracy
d2 %>% filter(Product == "TVs", Chip_type == "PlainChip") # correct
d2 %>% filter(Product == "Miscellaneous", Chip_type == "BiMech") # correct
d2 %>% filter(Product == "Monitors", Chip_type == "Classic") # NOT right! 
                    # there are 2 in and 2 out, but 1 in and 1 out match, 
                    # the other's are different colors, so the line's not drawn
d2 %>% filter(Product == "TVs", Chip_type == "Micro") # not correct; 
                    # that's because there is more in than out

最后一件事,我终于停下来了!垂直线——我放大了 'All'。这是同一图、相同缩放、相同 quasi-horizontal 线、相同 垂直 线的多个视图:

比方说,plotly 的所有规则都是 x、y 和颜色。它不关心其他数据,你没有那样绑定它(好吧,我没有)。