Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shiny: ggiraph output object is huge, goes beyond its height, overlaps content below it #83

Closed
daattali opened this issue Dec 4, 2017 · 17 comments

Comments

@daattali
Copy link

daattali commented Dec 4, 2017

Using this shiny app code (the output is taken directly from the documentation)

library(shiny)
library(ggplot2)
library(ggiraph)

ui <- fluidPage(
  ggiraphOutput("plot"),
  h1("FOO")
)

server <- function(input, output, session) {
  output$plot <- renderggiraph({
    dataset = iris
    dataset$tooltip = dataset$Species
    dataset$clickjs = paste0("alert(\"",dataset$Species, "\")" )
    
    gg_point = ggplot(dataset, aes(x = Sepal.Length, y = Petal.Width,
                                   color = Species, tooltip = tooltip, onclick = clickjs) ) +
      geom_point_interactive()
    
    ggiraph(code = {print(gg_point)})
  })
}

shinyApp(ui, server)

In the RStudio Viewer it looks fine. But in a browser (I'm using Chrome), the output gets wildly out of control, takes up way too much vertical space, outside of its allotted 500px, and overlaps content below it.

Here is a screenshot (any content below the plot gets swallowed)

image

This bug unfortunately makes ggiraph effectively unusable in a shiny app currently

ggiraph 0.4.1, shiny 1.0.5

@davidgohel
Copy link
Owner

davidgohel commented Dec 4, 2017

Dear Dean,

Using this shiny app code (the output is taken directly from the documentation)

Can you show me where is that example in the documentation?

This bug unfortunately makes ggiraph effectively unusable in a shiny app currently

Can you run the examples located in inst/shiny? On my computer, they are running as expected and I also have customers that are using it without any issue. If you are using Columns inside FluidRow, it should look better.

The widget is usually sized relative to its container, here the container is a fluidPage and its relative width is 90% (see argument width of ggiraph()).

@daattali
Copy link
Author

daattali commented Dec 4, 2017

  1. The entire code inside the renderggiraph is taken directly from the example usage in ?ggiraph

  2. I just tried the iris example, and it does work. But the ggiraph also does indeed take up an enormous amount of vertical space, outside of what it's supposed to occupy. It's true that it only takes up the necessary width according to its container, but the height goes well beyond. You can see this if you run my example code from before. Or even with the example in inst/shiny/iris - if you simply swap the text input and the ggiraph output (place the input after the output) then you'll see that the output goes on top of the input and much below it as well

I actually found the bug while using a column, I was using a width of 8 but the graph was taking up the entire page height-wise. Only if I go as low as width=4 then it becomes usabale, but then the graph itself is too narrow.

@daattali
Copy link
Author

daattali commented Dec 5, 2017

Note that within RStudio Viewer, the height is correct. When the app pops up into a real browser, the height is disregarded.

Something else I noticed is that setting a height property on the <svg> element seems to work. But I don't know anything about the internals of this package so that's probably not the correct solution.

However, changing the height also changes the width proportionally. Is it not possible to have the width and height set manually and not use the default proportion? This is useful is you need a long or tall plot

@davidgohel
Copy link
Owner

When viewing in Rstudio pane, the container is small and we can hardly see the issue; when viewing in an HTML page, the container is much bigger and you see the graph behaving the same than in Rstudio viewer. In markdown document, that's ok; in shiny applications, there can be unexpected behaviors as you reported.

The svg is generated with an R graphical device (as pdf or png), hence a width and a height must be defined first. Then htmlwidget has a sizing policy different from these settings. Having arguments width_svg > height_svg may help as it would create a graph with an aspect ratio greater than 1.

However, this is a workaround, not a solution.

Solving that implies a refactoring of sizing policy (initial feeling is that I need to stop using htmlwidgets sizing policies). I am planning to work on that soon (I need to complete few other things on other repositories).

@daattali
Copy link
Author

daattali commented Dec 5, 2017 via email

@davidgohel
Copy link
Owner

htmlwidget height is ignored, yes.

I will try to solve that soon.

@daattali
Copy link
Author

@davidgohel do you think this will be solved within December? I love the plots and really want to keep them but I need to know if to wait or if to change to a different package for a client

@davidgohel
Copy link
Owner

That's the plan. I am on it right now... I think shiny (standard and flexdashboard) is ok, still struggling with sizes within xaringan. Hopefully tomorrow evening, this will be on gh.

@daattali
Copy link
Author

Awesome, glad to hear!!! So happy I can continue to use this

@daattali
Copy link
Author

If you want to push to a dev branch so that it's not on master while you're still working on it, I'd be happy to test it out from a branch

@davidgohel
Copy link
Owner

I published branch sizing. Should be ok for shiny and flexdashboard - not ok on shinydashboard... WIP

@daattali
Copy link
Author

I just tried installing from that branch and running the same code as above. There is one improvement, the div that comes after the plot does go below the plot now. But the plot still seems to completely disregard its requested height and width, it still takes up the entire screen. Even if I add width=400, height=500 the plot still takes up the my entire window. Do you think there's a way to make the plot respect its dimensions?

@davidgohel
Copy link
Owner

htmlwidget height and width are ignored in this version.

For now, use a workaround like this one:

ui <- fluidPage(
  div(style="width:400px;height:400px;", ggiraphOutput("plot")),
  h1("FOO")
)

@daattali
Copy link
Author

You're right, adding the width to a container does make it respect its width. Thanks for responding so fast and for your work!

I think the height is still being ignored though, because: (a) setting only the width works, (b) setting only the height does nothing, (c) setting the height and the width together doesn't change the height. It seems to always just produce a square based on the width, and ignore the height.

If I have a bar plot that needs to be wide because there are many bars but it doesn't need to be very tall, it will either be a small square which means it's hard to read the labels, or it will be a huge square if I make it wide enough. But ideally I should be able to have a bar graph that is wide and short, by setting both the width and the height. I'm hoping you have a solution for that too :)

@davidgohel
Copy link
Owner

Have a try with the new commit. It does now respect the width and height of ggiraphOutput.

About the comment:

If I have a bar plot that needs to be wide because there are many bars but it doesn't need to be very tall[...]

The plot is not produced by the javascript (as plotly, dygraphs, rbokeh) and when created, it does not know what are the values of width and height of the HTML container. It is created by an R graphical device and theses are corresponding to classical arguments of R devices {width, height} (i.e pdf, png, svg). You need to play with arguments width_svg and height_svg, it defines width and height and the aspect ratio of the graphic (width/height). I think you produced a square because the default values are 6*6 (were as I changed them to 6*5).

library(shiny)
library(ggiraph)
library(ggplot2)

dataset = mtcars
dataset$carname = row.names(mtcars)

ui <- fluidPage(

   titlePanel("ggiraph aspect ratio illustration"),

   sidebarLayout(
      sidebarPanel(
         sliderInput("width", "width in inches:", min = 2, max = 10, value = 6),
         sliderInput("height", "height in inches:", min = 2, max = 10, value = 6)
      ),

      mainPanel(
         ggiraphOutput("plot"),
         h2("check overlap")
      )
   )
)

server <- function(input, output) {

   output$plot <- renderggiraph({
     gg_point = ggplot( data = dataset,
       mapping = aes(x = wt, y = qsec, color = disp,
                     tooltip = carname, data_id = carname) ) +
       geom_point_interactive() + theme_minimal() +
       theme(plot.background = element_rect(fill = "wheat"))

     ggiraph(ggobj = gg_point, width = .7, width_svg = input$width, height_svg = input$height)
   })
}

shinyApp(ui = ui, server = server)

@daattali
Copy link
Author

Ah I understand, so width and height determine the outer bounding box and width_svg and height_svg determines the proportions. I'll have to see how I work with that in a shiny app, where pixels are the working unit rather than inches. Is there a way to specify pixels per inch for the svg? And we don't need to use the outer div to specify width/height, I should only use the ggiraphOutput() for that, right?

@davidgohel
Copy link
Owner

Exactly, well said.

Is there a way to specify pixels per inch for the svg

One inch is 72 pixels or 72 px is 1 inch.

And we don't need to use the outer div to specify width/height, I should only use the ggiraphOutput() for that, right?

Yes, you can use argument widthand height of ggiraphOutput() to define the outer bounding box.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants