mevers / shiny_STRING

3 stars 0 forks source link

Save network as jpg, png or pdf #1

Closed Jemkon closed 4 years ago

Jemkon commented 4 years ago

Hi,

Many thanks for sharing an amazing work. I was wondering if the STRING Network can be saved as either JPG, PNG or PDF.

Any idea how can I save the network as image?

Any help much appreciated.

Regards, Jemkon

mevers commented 4 years ago

Oof, that's going to be tricky. STRING offers different API methods; some allow you to save the network directly as a low/high-res PNG. In the case here however, I use javascript:getSTRING(...) which returns an embedded & interactive SVG network.

As far as I can see, there's no straightforward way to save the network as a raster image or PDF. That being said: There may a hacky javascript way to grab the SVG (based on the <svg id=...> tag?), then convert to canvas to raster; link this to an actionButton in Shiny and -- ignoring any details -- Bob's your uncle.

I may review this if/when I have some spare time; in the meantime, happy to hear any other suggestions!

Jemkon commented 4 years ago

@mevers Many thanks.

The following URL creates static network into browser and can get the PNG image: https://string-db.org/api/image/network?identifiers=PTCH1%0dSHH%0dGLI1%0dSMO%0dGLI3

I tired using this approach in Shiny but unable to download the image. basically I am creating a url with genes to create network and then provide that URL to htmlwidget to download image from html to png.

PPI_input <- c("PTCH1", "SHH", "GLI1", "SMO", "GLI3")

### downloading the image
  output$SavePPI_button <- downloadHandler(
    filename =  function() {
      paste0('STRINGDB_PPI', ".png")
    },
    # content is a function with argument file. content writes the plot to the device
    content = function(file) {
  srch <- paste0(PPI_input, collapse = "%0d")
  downloadURL <- paste0("https://string-db.org/api/image/network?identifiers=",srch)
        htmlwidgets::saveWidget(widget = downloadURL, file = "temp.html", selfcontained = FALSE)
        webshot::webshot(url = "temp.html", file = file)
    } 
  )

Any ideas?

Regards, Jemkon

mevers commented 4 years ago

I don't think you can use htmlwidgets::saveWidget here, as the query returns a static PNG. You can however use httr::GET.

Here's a minimal shiny app example

library(shiny)
library(httr)

PPI_input <- c("PTCH1", "SHH", "GLI1", "SMO", "GLI3")
baseurl <- "https://string-db.org/api/image/network?identifiers="

ui <- fluidPage(
    actionButton("button", "Save PPI as PNG")
)

server <- function(input, output, session) {
    observeEvent(input$button, {
        url <- sprintf("%s%s", baseurl, paste0(PPI_input, collapse = "%0d"))
        print(url)
        GET(url, write_disk("STRINGDB_PPI.png", overwrite = TRUE))
    })
}

shinyApp(ui, server)

Clicking on the button creates a PNG

STRINGDB_PPI

I should point out that this method uses a different API method, and as such the interactive SVG network and the static PNG don't necessarily match. In other words, if you start moving the nodes around in the interactive network, then download the PNG, the raster image will not reflect the new node layout from the interactive plot.

Either way, I'll also add an option to download a static PNG in the main app.

Thanks for the suggestion @Jemkon

mevers commented 4 years ago

I've now included a PNG download option that converts the SVG network to a PNG using the previously mentioned "hacky JS way". It ended up being not too "hacky" after all. The newest commit now uses this method (which replaces the method from the previous commit).

The advantage of this method is that we're not using two different API methods (and queries), and that changes in the SVG network are reflected in the PNG (meaning: if you drag the nodes around, then save as a PNG, the raster image will reflect the new node layout).

A big help was the Stack Overflow post Save inline SVG as JPEG/PNG/SVG, in particular the answer by KhalilRavanna.

Jemkon commented 4 years ago

I've now included a PNG download option that converts the SVG network to a PNG using the previously mentioned "hacky JS way". It ended up being not too "hacky" after all. The newest commit now uses this method (which replaces the method from the previous commit).

The advantage of this method is that we're not using two different API methods (and queries), and that changes in the SVG network are reflected in the PNG (meaning: if you drag the nodes around, then save as a PNG, the raster image will reflect the new node layout).

A big help was the Stack Overflow post Save inline SVG as JPEG/PNG/SVG, in particular the answer by KhalilRavanna.

Simply brilliant... Many thanks, for rapid update. It works like a charm. Just a quick question about API calls. Is there a limit on input genes? If there is, how do I get network for 100+ genes?

I see the nodes are clickable but not the edges. Would it be possible to click edges to get more info about evidence?

Really appreciated your help.

Regards, Jemkon

mevers commented 4 years ago

@Jemkon

I'm not sure about the maximum number of (concurrent) requests. That would be a server-side configuration. Other than trying by trial-and-error your best bet would be to ask the STRING API maintainers directly.

Edges are not clickable; that's (sadly) not something I can change, but is part of what javascript:getSTRING and the STRING API provides.