5

The below code generates two plots using ggplot and ggplotly. Despite of using the layout() to ggplotly the legend is still at the right side. The legend is required to be at the bottom. Could anyone help to move the legend to bottom in the ggplotly? I have tried the solution at R + shiny + plotly: ggplotly moves the legend to the right and is not working here. Can someone help if im missing the obvious.

measure<-c("MSAT","MSAT","GPA","MSAT","MSAT","GPA","GPA","GPA")
score<-c(500, 490, 2.9, 759, 550, 1.2, 3.1, 3.2)
data<-data.frame(measure,score)


ui <- fluidPage(
  mainPanel(
    plotOutput("myplot" ),
    plotlyOutput("myplot2" )
  )
)

server <- function(input, output) {
  myplot <- reactive({
    gpl1 <- ggplot(data,aes(y=reorder(measure, score),x=score,fill=score)) +
      geom_bar(stat="identity")+
      theme(legend.position="bottom")+
      xlab("x")+
      ylab("y")+
      labs(title = NULL)
    gpl1
  })
  
  myplot2 <- reactive({
    gpl2 <- ggplot(data,aes(y=reorder(measure, score),x=score,fill=score)) +
      geom_bar(stat="identity") +
      theme(legend.position="bottom")+
      xlab("x")+
      ylab("y")+
      labs(title = NULL)
    ggplotly(gpl2) %>% 
      layout(legend = list(orientation = 'h', x = 0.45, y = 1.1))
  })
  output$myplot <- renderPlot({
    myplot()
  })
  output$myplot2 <- renderPlotly({
    myplot2()
  })
}
  
shinyApp(ui = ui, server = server)
ismirsehregal
  • 30,045
  • 5
  • 31
  • 78
chas
  • 1,565
  • 5
  • 26
  • 54
  • The reason the top plot is structured that way is because of the themes you chose. – neuron Oct 07 '21 at 16:50
  • i need to render this plot in a shiny app as interactive plot `renderplotly` to `plotlyOutput` . So i am converting to `ggplotly(p)` – chas Oct 07 '21 at 16:50
  • Sorry, I corrected my comment. I didn't notice that you were saying `ggplotly` and not `ggplot` – neuron Oct 07 '21 at 16:51
  • Does this answer your question? [R + shiny + plotly: ggplotly moves the legend to the right](https://stackoverflow.com/questions/69306154/r-shiny-plotly-ggplotly-moves-the-legend-to-the-right) – lz100 Oct 07 '21 at 22:15
  • 1
    `ggplotly(pp) %>% layout(xaxis = list(side = "top"),legend = list(side="bottom"))` the axis is moved to top but the legend is still on the right. Also tried `ggplotly(pp) %>% layout(xaxis = list(side = "top"), legend = list(orientation = "h", x = 0.4, y = 0.2))` which also did not change the legend position. – chas Oct 08 '21 at 23:08
  • You are commenting here and on the other post but just not providing some reproducible code, we can't help you. – lz100 Oct 09 '21 at 00:30
  • Original post is updated with reproducible code. – chas Oct 09 '21 at 09:28
  • Any hints now with the reproducible code? – chas Oct 13 '21 at 10:53
  • I have tried installing older versions of both `plotly` and `ggplot2` (which haven't been updated since that other answer anyway, but thought I'd try). Very confused how this worked in September (https://stackoverflow.com/a/69306461/9096420), but not now (less than two months later). – Dylan_Gomes Nov 10 '21 at 20:25

3 Answers3

2

The problem here is, that you are dealing with a colorbar not a legend.

Currently plotly does not offer horizontal colorbars.

Also changing the position of a colorbar seems to be buggy in the ggplotly context:

library(shiny)
library(plotly)

measure<-c("MSAT","MSAT","GPA","MSAT","MSAT","GPA","GPA","GPA")
score<-c(500, 490, 2.9, 759, 550, 1.2, 3.1, 3.2)
data<-data.frame(measure,score)


ui <- fluidPage(
  mainPanel(
    plotOutput("myplot" ),
    plotlyOutput("myplot2" )
  )
)

server <- function(input, output) {
  myplot <- reactive({
    gpl1 <- ggplot(data,aes(y=reorder(measure, score),x=score,fill=score)) +
      geom_bar(stat="identity")+
      theme(legend.position="bottom")+
      xlab("x")+
      ylab("y")+
      labs(title = NULL)
    gpl1
  })
  
  myplot2 <- reactive({
    fig <- ggplotly(myplot())
    fig <- style(fig, marker = list(colorbar = list(xanchor = "center", yanchor = "center", x = 0.5, y = -1, title = "test")), traces = NULL) # try traces = 1 or 1:2
    # browser()
    # plotly_json(fig)
  })
  
  output$myplot <- renderPlot({
    myplot()
  })
  
  output$myplot2 <- renderPlotly({
    myplot2()
  })
}

shinyApp(ui = ui, server = server)

Accordingly, for now I'd recommend not to modify the colorbar and use the defaults.

ismirsehregal
  • 30,045
  • 5
  • 31
  • 78
2

As @ismirsehregal mentioned plotly does not yet support the horizontal colorbar, and the colorbar is present to support the continuous-valued fill attribute. So until plotly supports that orientation an alternative solution might serve temporarily: change the fill from continuous value to a discrete value. Here is the reactive using (a) a cut for the discrete values, and (b) plotly anchors for the bottom legend.

myplot2 <- reactive({
  gpl2 <- ggplot(data,aes(y=reorder(measure, score),
                          x=score,
                          fill=cut(score, breaks=seq(0,800,100)))) +
      geom_bar(stat="identity") +
      labs(x='x',y='y',title=NULL,fill='Score') +
      theme(legend.position = 'bottom') +
      # scale_fill_stepsn(colours = terrain.colors(10),n.breaks=10)
      scale_fill_viridis_d()

    ggplotly(gpl2) %>%
      plotly::layout(legend=list(x=0, 
                                 xanchor='left',
                                 yanchor='bottom',
                                 orientation='h'))    
})

plotly bottom legend

mrbcuda
  • 580
  • 7
  • 16
1

Okay this isn't a full answer, but it is a start that might help someone else pinpoint the problem, and it is too long to fit into a comment. It is possible it is worth opening up an issue, although I am not sure where (i.e. within what package) the problem lies.

I re-ran the code from R + shiny + plotly: ggplotly moves the legend to the right and it works as it should, but for some reason yours doesn't. The only difference is that your fill is continuous, whereas the fill in that one is categorical.

If you add a categorical group here for score:

measure<-c("MSAT","MSAT","GPA","MSAT","MSAT","GPA","GPA","GPA")
score<-c(500, 490, 2.9, 759, 550, 1.2, 3.1, 3.2)
data<-data.frame(measure,score,score.f=as.factor(score))

Then the code you have works. You need to modify the gpl2 object with fill=score.f (instead of fill=score), and also need to change the y value in the layout to get the legend to the bottom:

ggplotly(gpl2) %>% 
            layout(legend = list(orientation = 'h', x = 0.45, y = -.07))

enter image description here

Yet, as soon as you change the fill group to a continuous

score<-c(500, 490, 2.9, 759, 550, 1.2, 3.1, 3.2)
data<-data.frame(measure,score,score.f=score)

The legend goes back to being on the right:

enter image description here

Dylan_Gomes
  • 2,066
  • 14
  • 29