[英]R Plotly: Move the legend title above the legends in the horizontal legend position
I have a limitation in the window size, which requires me to have my plotly
(converted using ggplotly
) figures to have:我的窗口大小有限制,这要求我的
plotly
(使用ggplotly
转换)数字具有:
ggplot
HERE )ggplot
HERE ) Here is my code which the plotly part needs to be modified only:这是我的代码,只需要修改 plotly 部分:
library(shiny)
library(dplyr)
library(ggplot2)
library(plotly)
ui <- fluidPage(
uiOutput("allplots")
)
server <- function(input, output, session) {
output$allplots <- renderUI({
test <-structure(list(
Day = c(1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L,
2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L),
Drug = c("A", "B", "B", "C","A", "C", "A", "B", "C", "A", "B", "C", "A", "C", "A", "B", "B","C"),
Sex = c("Female", "Male", "Female", "Female", "Male", "Male","Male", "Female", "Male", "Female", "Female",
"Male", "Male", "Female", "Female", "Male", "Male", "Female"),
Y = c(2.192306074, 4.551912798, 1.574070652, -0.143946163, 5.144422967, 5.724705829,
2.691617258, -3.0289955, 0.338102762, -0.558581233, -2.942620032, 1.024670497, 2.264980803,
2.103722883, 2.091621938, 1.535299922, 1.618399767, 0.136160703),
DrugSex = structure(c(1L, 4L, 3L, 5L, 2L, 6L, 2L, 3L, 6L, 1L, 3L, 6L, 2L, 5L, 1L, 4L, 4L, 5L),
levels = c("A,Female", "A,Male", "B,Female", "B,Male", "C,Female", "C,Male"),
class = "factor"),testNo = 1:18), row.names = c(NA,-18L), class = "data.frame")
Xs <- c("testNo", "Day")
plots <- lapply(Xs, function(x){
renderPlotly({
p <-test %>% ggplot(aes_string(x = "DrugSex", y = x)) +
geom_point(aes(color = Drug, shape = DrugSex))+
labs(x = paste0("DrugSex"), y = x) +
scale_shape_manual(values=1:length(unique(test$DrugSex))) +
guides(colour = guide_legend(title.position="top", title.hjust = 0.5),
shape = guide_legend(title.position="top", title.hjust = 0.5)) +
theme(legend.position = 'bottom',
legend.key=element_blank() #transparent legend panel
)
ggplotly(p) %>%
layout(
legend = list(orientation = 'h', xanchor = 'center', x = .5, y = -1.5))
})
})
fluidRow(column(width = 4, plots[[1]]),
column(width = 4, plots[[2]]))
})
}
shinyApp(ui, server)
Here is the current output:这是当前的输出:
For the second part of my question, by stacking I mean an output similar like the figure below in which every row contains two legends:对于我的问题的第二部分,堆叠是指类似于下图的输出,其中每一行都包含两个图例:
UPDATE: In Q1, I also want to know how I can resolve the problem with partially shown legends and titles when we have many legends, as in the picture below, Would it be useful if we could move the title of a legend to the top of the list of legends?更新:在第一季度,我还想知道当我们有很多图例时如何解决部分显示的图例和标题的问题,如下图所示,如果我们可以将图例的标题移到顶部会有用吗传奇列表的? If yes, how?
如果是,如何?
When I run your code, I don't get a legend for either plot.当我运行你的代码时,我没有得到任何一个情节的图例。 However, I can at least answer that yes—you could move the title to the top in a roundabout way.
但是,我至少可以回答是——您可以将标题以迂回的方式移至顶部。 However, since your
xaxis
title is the legend title, you could just make the legend title blank.但是,由于您的
xaxis
标题是图例标题,您可以将图例标题设为空白。
If the plot is narrow and the data is long, you could achieve a stacked legend, but it will change with the width of the viewing area.如果图很窄,数据很长,你可以实现堆叠图例,但它会随着查看区域的宽度而变化。 (You could control the size of the viewing area.)
(您可以控制查看区域的大小。)
Alternatively, it looks like Plotly added a new feature in the last few months, but Plotly for R isn't using the latest version of Plotly.或者,看起来 Plotly 在过去几个月中添加了一项新功能,但 Plotly for R 并未使用最新版本的 Plotly。 You could change the dependency and control the width that way (stacking, all that jazz).
您可以更改依赖关系并以这种方式控制宽度(堆叠,所有爵士乐)。
However, whether you control the plot viewing size or the legend entry size, it won't split the legends.但是,无论您控制绘图查看大小还是图例条目大小,它都不会拆分图例。
One legend...I know there are issues with subplot
in Plotly and Shiny.一个传奇......我知道
subplot
和 Shiny 中的子图存在问题。 However, it works for me here.但是,它在这里对我有用。
Since the xaxis
is the legend title, you could erase the legend title.由于
xaxis
是图例标题,您可以删除图例标题。
Since I am not getting a legend at all, this also turns it on.因为我根本没有得到图例,所以这也打开了它。
fixLeg <- function(plt){
plt <- plotly_build(plt)
nms <- plt$x$layout$xaxis$ticktext
plt$x$layout$legend$title$text <- ""
map(1:length(plt$x$data),
function(k) {
plt$x$data[[k]]$name <<- nms[[k]]
plt$x$data[[k]]$showlegend <<- TRUE
})
plt
}
I modified the call, to add showlegend
, modify y
in legend
and add the call for fixLeg()
.我修改了调用,添加
showlegend
,修改legend
中的y
并添加对fixLeg()
的调用。
plots <- lapply(Xs, function(x){
renderPlotly({
p <-test %>% ggplot(aes_string(x = "DrugSex", y = x)) +
geom_point(aes(color = Drug, shape = DrugSex))+
labs(x = paste0("DrugSex"), y = x) +
scale_shape_manual(values=1:length(unique(test$DrugSex))) +
guides(colour = guide_legend(title.position="top", title.hjust = 0.5),
shape = guide_legend(title.position="top", title.hjust = 0.5)) +
theme(legend.position = 'bottom',
legend.key=element_blank()) #transparent legend panel
ggplotly(p) %>% fixLeg() %>% # <---- add legend/remove legend title
layout(showlegend = T,
legend = list(orientation = 'h', xanchor = 'center',
x = .5, y = -.3)) # <---- changed y
})
})
A stacked legend, whether it originated as one legend or many legends.一个堆叠的传奇,无论它起源于一个传奇还是多个传奇。 For this, I'm going to change the Plotly dependency to the latest version of Plotly JS, I'll use a function to do that.
为此,我将把 Plotly 依赖项更改为最新版本的 Plotly JS,我将使用一个函数来执行此操作。 This function will allow the parameters of
entrywidth
and entrywidthmode
to work in R.此函数将允许
entrywidth
和entrywidthmode
的参数在 R 中工作。
fixLeg2 <- function(plt){
plt <- plotly_build(plt)
# changes to dependency so that entrywidth/entrywidthmode work
plt$dependencies[[5]]$src$href = "https://cdn.plot.ly"
plt$dependencies[[5]]$script = "plotly-2.16.1.min.js"
plt$dependencies[[5]]$local = FALSE
plt$dependencies[[5]]$package = NULL
# changes to object
nms <- plt$x$layout$xaxis$ticktext
plt$x$layout$legend$title$text <- ""
map(1:length(plt$x$data),
function(k) {
plt$x$data[[k]]$name <<- nms[[k]]
plt$x$data[[k]]$legendgroup <<- nms[[k]]
plt$x$data[[k]]$showlegend <<- TRUE
})
plt
}
To make sure that Shiny goes to get the CDN from the web, you'll add something else to the user interface ( ui
).为确保 Shiny 从 Web 获取 CDN,您需要向用户界面 (
ui
) 添加其他内容。 This addition requires the use of htmltools
.此添加需要使用
htmltools
。 The Shiny app may work without this addition. Shiny 应用程序可以在没有此添加的情况下运行。 However, it will be intermittent at best.
但是,它充其量是间歇性的。
library(shiny)
library(dplyr)
library(ggplot2)
library(plotly)
library(htmltools)
newDep <- htmlDependency(name = "plotly-latest",
version = "2.16.1",
src = list(href = "https://cdn.plot.ly"),
script = "plotly-2.16.1.min.js")
ui <- fluidPage(
createWebDependency(newDep),
uiOutput("allplots")
)
Then with the plots, add an entrywidth
.然后在绘图中添加一个
entrywidth
。 Additionally, change the function call for fixLeg
to fixLeg2
.此外,将
fixLeg2
fixLeg
By the way entrywidth
is the width in pixels of the text component of a legend entry.顺便说一下,
entrywidth
是图例条目的文本组件的宽度(以像素为单位)。 The symbol, dot, line, or colored part is item
in the legend.符号、点、线或彩色部分是图例中的
item
。 You can control that size, too.您也可以控制该尺寸。 I'm pretty sure that control is fairly new, as well.
我很确定控件也是相当新的。
plots <- lapply(Xs, function(x){
renderPlotly({
p <-test %>% ggplot(aes_string(x = "DrugSex", y = x)) +
geom_point(aes(color = Drug, shape = DrugSex))+
labs(x = paste0("DrugSex"), y = x) +
scale_shape_manual(values=1:length(unique(test$DrugSex))) +
guides(colour = guide_legend(title.position="top", title.hjust = 0.5),
shape = guide_legend(title.position="top", title.hjust = 0.5)) +
theme(legend.position = 'bottom',
legend.key=element_blank() #transparent legend panel
)
ggplotly(p) %>% fixLeg2() %>% # <------- I'm new
layout(showlegend = T,
legend = list(orientation = 'h', xanchor = 'center',
x = .5, y = -.3, entrywidth = 100)) # <- entry width
})
})
This is how it's changed:这是它的变化方式:
In your question, you had specifically asked about when there is more than one legend, but your plots in this question only have one.在你的问题中,你特别询问了何时有多个传说,但你在这个问题中的情节只有一个。 I've taken this plot from a previous question.
我从上一个问题中获取了这个情节。 (Where
df
is extremely similar to test
in this question.) (其中
df
与此问题中的test
极为相似。)
p <- df %>% ggplot(aes(x = DrugSex, y = Y)) +
geom_point(aes(color = Drug, shape = DrugSex)) +
geom_segment(data = df_means, aes(x=x-0.25, xend=x+0.25, y=Mean, yend=Mean, color=
color),inherit.aes = F, show.legend = F)+
theme(legend.position = 'bottom',
legend.key=element_blank() #transparent legend panel
)
I have to change the call to change the dependencies a bit, because this plot isn't in Shiny.我必须更改调用以稍微更改依赖项,因为该图不在 Shiny 中。 Really, I've just added one new line (
src$file = NULL
).真的,我刚刚添加了一个新行(
src$file = NULL
)。
fixLeg3 <- function(plt) {
# changes to dependency so that entrywidth/entrywidthmode work
plt$dependencies[[5]]$src$file = NULL
plt$dependencies[[5]]$src$href = "https://cdn.plot.ly"
plt$dependencies[[5]]$script = "plotly-2.16.1.min.js"
plt$dependencies[[5]]$local = FALSE
plt$dependencies[[5]]$package = NULL
plt
}
I've added a new parameter entrywidthmode
.我添加了一个新参数
entrywidthmode
。 This is default pixels
.这是默认
pixels
。 However you can use fraction
as in a fraction of the plot.但是,您可以在情节的一小部分中使用
fraction
。 If I set it to.3 (so there's still room for the title), No matter how big I make this plot, only three legend entries are going on a single line.如果我将它设置为 .3(这样标题还有空间),无论我把这个图画得有多大,一行上只有三个图例条目。
ggplotly(p) %>% fixLeg3() %>%
layout(legend = list(orientation = "h",
y = -.3, entrywidthmode = "fraction",
entrywidth = .3))
When it comes to consolidating the legend, Plotly's subplot
can do it for you.在巩固图例方面,
subplot
的子图可以为您完成。 However, it won't do it without intervention.但是,如果没有干预,它不会这样做。 That's because you can select a legend item it hides or shows in the plot.
那是因为您可以选择它在图中隐藏或显示的图例项。 You can use
legendgroups
to get around it.您可以使用
legendgroups
来绕过它。 This will still allow entry selection by clicking on a legend item, but it will affect both plots.这仍将允许通过单击图例项来选择条目,但它会影响两个图。
To use legend grouping and have a consolidated legend, you have to designate the legend group of each trace, and you have to hide all but one trace within each legend group from the legend.要使用图例分组并获得统一的图例,您必须指定每条迹线的图例组,并且必须从图例中隐藏每个图例组中除一条迹线以外的所有迹线。 Here's a simpler example.
这是一个更简单的例子。 (By the way, hiding it in
ggplot
does nothing!) (顺便说一下,将它隐藏在
ggplot
中什么都不做!)
pp1 <- pp2 <- ggplot(test, # first plot, keep the legend
aes(x = Drug, y = Y, color = Drug, shape = DrugSex)) +
geom_point()
p2 <- ggplotly(pp2) # hide the legend in this plot
invisible(lapply(1:length(p2$x$data),
function(k) {
p2$x$data[[k]]$showlegend <<- FALSE # change in global
}))
subplot(ggplotly(pp1), p2) %>% # put it together
layout(showlegend = T,
legend = list(traceorder = "grouped", # <- make sure this is called first!!
orientation = "h", x = .5, xanchor = "center",
valign = "bottom"))
In Shiny, don't use renderPlotly
to show a subplot
.在 Shiny 中,不要使用
renderPlotly
来显示subplot
。 Just use renderUI
and call subplot
like you would in an R script.只需使用
renderUI
并像在 R 脚本中一样调用subplot
。
If you find that a combined legend won't orient horizontally, make sure that traceorder
is called before orientation
.如果您发现组合图例不会水平定向,请确保在
orientation
之前调用traceorder
。 It shouldn't matter, but it does.这应该无关紧要,但确实如此。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.