繁体   English   中英

R Plotly:将图例标题移动到水平图例位置的图例上方

[英]R Plotly: Move the legend title above the legends in the horizontal legend position

我的窗口大小有限制,这要求我的plotly (使用ggplotly转换)数字具有:

  1. 图例标题位于图例上方(类似于ggplot HERE
  2. 例如,如果可能,将图例堆叠在一起,其中每行包含两个图例。
  3. 底部水平放置的两个地块是否可以有一个图例?

这是我的代码,只需要修改 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)

这是当前的输出:

在此处输入图像描述

对于我的问题的第二部分,堆叠是指类似于下图的输出,其中每一行都包含两个图例:

在此处输入图像描述

更新:在第一季度,我还想知道当我们有很多图例时如何解决部分显示的图例和标题的问题,如下图所示,如果我们可以将图例的标题移到顶部会有用吗传奇列表的? 如果是,如何?

在此处输入图像描述

当我运行你的代码时,我没有得到任何一个情节的图例。 但是,我至少可以回答是——您可以将标题以迂回的方式移至顶部。 但是,由于您的xaxis标题是图例标题,您可以将图例标题设为空白。

如果图很窄,数据很长,你可以实现堆叠图例,但它会随着查看区域的宽度而变化。 (您可以控制查看区域的大小。)

或者,看起来 Plotly 在过去几个月中添加了一项新功能,但 Plotly for R 并未使用最新版本的 Plotly。 您可以更改依赖关系并以这种方式控制宽度(堆叠,所有爵士乐)。

但是,无论您控制绘图查看大小还是图例条目大小,它都不会拆分图例。

一个传奇......我知道subplot和 Shiny 中的子图存在问题。 但是,它在这里对我有用。

Q1

由于xaxis是图例标题,您可以删除图例标题。

因为我根本没有得到图例,所以这也打开了它。

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
}

我修改了调用,添加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
  })
})

在此处输入图像描述

Q2

一个堆叠的传奇,无论它起源于一个传奇还是多个传奇。 为此,我将把 Plotly 依赖项更改为最新版本的 Plotly JS,我将使用一个函数来执行此操作。 此函数将允许entrywidthentrywidthmode的参数在 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
}

为确保 Shiny 从 Web 获取 CDN,您需要向用户界面 ( ui ) 添加其他内容。 此添加需要使用htmltools Shiny 应用程序可以在没有此添加的情况下运行。 但是,它充其量是间歇性的。

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")
)

然后在绘图中添加一个entrywidth 此外,将fixLeg2 fixLeg

顺便说一下, entrywidth是图例条目的文本组件的宽度(以像素为单位)。 符号、点、线或彩色部分是图例中的item 您也可以控制该尺寸。 我很确定控件也是相当新的。

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
  })
})

这是它的变化方式:

在此处输入图像描述

在你的问题中,你特别询问了何时有多个传说,但你在这个问题中的情节只有一个。 我从上一个问题中获取了这个情节。 (其中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
  )

我必须更改调用以稍微更改依赖项,因为该图不在 Shiny 中。 真的,我刚刚添加了一个新行( 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
}

我添加了一个新参数entrywidthmode 这是默认pixels 但是,您可以在情节的一小部分中使用fraction 如果我将它设置为 .3(这样标题还有空间),无论我把这个图画得有多大,一行上只有三个图例条目。

ggplotly(p) %>% fixLeg3() %>% 
  layout(legend = list(orientation = "h", 
                       y = -.3, entrywidthmode = "fraction",
                       entrywidth = .3))

在此处输入图像描述 在此处输入图像描述 在此处输入图像描述

Q3

在巩固图例方面, subplot的子图可以为您完成。 但是,如果没有干预,它不会这样做。 那是因为您可以选择它在图中隐藏或显示的图例项。 您可以使用legendgroups来绕过它。 这仍将允许通过单击图例项来选择条目,但它会影响两个图。

要使用图例分组并获得统一的图例,您必须指定每条迹线的图例组,并且必须从图例中隐藏每个图例组中除一条迹线以外的所有迹线。 这是一个更简单的例子。 (顺便说一下,将它隐藏在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"))

在此处输入图像描述

在 Shiny 中,不要使用renderPlotly来显示subplot 只需使用renderUI并像在 R 脚本中一样调用subplot

如果您发现组合图例不会水平定向,请确保在orientation之前调用traceorder 应该无关紧要,但确实如此。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM