R 巧妙地分离功能图例
R plotly separate functional legends
我想通过 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)))
这是结果:
如你所见,colorbar乱了,两个类别纠缠在一起
我需要为 age
(年轻与年老)和 gender
(男与女)分别创建图例,它们可以相互独立地单击。这将是预期的结果:
编辑 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
图的解决方案,而不是 post hoc ggplotly()
修复已在其他 post 中提出。
编辑 2
尽管当前的答案确实解开了两个图例(age
和 gender
),但它们不起作用。例如,如果您单击 young
级别,整个 age
图例将切换为 on/off。这里的 objective 是每个图例的每个子级别都可以独立切换,通过点击图例的级别,点将相应地 show/hide。
这不是您要找的。不过,我能够创建一个有意义的颜色条。
我删除了组间交互的调用并创建了一个单独的跟踪。然后我创建了图例组并命名它们,为 gender
和 age
创建单独的图例。当我从调用中拉出 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')
我不确定这是否正是您想要的。我尝试使用两个 markers
制作年龄和性别的图例。图例可独立点击,但我不确定这是否是您希望它们可点击的方式。也可以单击颜色条。您可以使用此代码:
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)))
输出如下所示:
Plotly 似乎并不容易支持这一点,因为不同的指南链接到多个跟踪。所以取消选择例如“年龄”轨迹上的“旧”不会从“性别”轨迹的单独点集中删除任何内容。
这是使用 crosstalk
和 SharedData
数据对象的解决方法。这不是(取消)选择 plotly traces,而是在 plotly 使用的数据集上使用过滤器。它在技术上实现了所请求的选择行为,但它是否是一个可行的解决方案取决于最终的应用程序。如果该机制适合您,可能有一些方法可以调整样式和布局以使其更加 plotly-ish。
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))
)
)
编辑:将所有复选框初始化为“选中”
我只能通过修改输出 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)
我想通过 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)))
这是结果:
如你所见,colorbar乱了,两个类别纠缠在一起
我需要为 age
(年轻与年老)和 gender
(男与女)分别创建图例,它们可以相互独立地单击。这将是预期的结果:
编辑 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
图的解决方案,而不是 post hoc ggplotly()
修复已在其他 post 中提出。
编辑 2
尽管当前的答案确实解开了两个图例(age
和 gender
),但它们不起作用。例如,如果您单击 young
级别,整个 age
图例将切换为 on/off。这里的 objective 是每个图例的每个子级别都可以独立切换,通过点击图例的级别,点将相应地 show/hide。
这不是您要找的。不过,我能够创建一个有意义的颜色条。
我删除了组间交互的调用并创建了一个单独的跟踪。然后我创建了图例组并命名它们,为 gender
和 age
创建单独的图例。当我从调用中拉出 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')
我不确定这是否正是您想要的。我尝试使用两个 markers
制作年龄和性别的图例。图例可独立点击,但我不确定这是否是您希望它们可点击的方式。也可以单击颜色条。您可以使用此代码:
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)))
输出如下所示:
Plotly 似乎并不容易支持这一点,因为不同的指南链接到多个跟踪。所以取消选择例如“年龄”轨迹上的“旧”不会从“性别”轨迹的单独点集中删除任何内容。
这是使用 crosstalk
和 SharedData
数据对象的解决方法。这不是(取消)选择 plotly traces,而是在 plotly 使用的数据集上使用过滤器。它在技术上实现了所请求的选择行为,但它是否是一个可行的解决方案取决于最终的应用程序。如果该机制适合您,可能有一些方法可以调整样式和布局以使其更加 plotly-ish。
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))
)
)
编辑:将所有复选框初始化为“选中”
我只能通过修改输出 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)