Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrieve pictures from API with R

Tags:

json

r

api

httr

I have never worked with APIs so this is my first try, I don't even know if what I'm trying to do is possible.

I'm trying to obtain pictures of cells from the SwissBioPics API (https://www.npmjs.com/package/%40swissprot/swissbiopics%2Dvisualizer) and have them in my R session.

res <-  httr::GET('https://www.swissbiopics.org/static/swissbiopics.js',
                     query = list(taxisid = '9606', sls= 'SL0073',gos = '0005641'))
result <- httr::content(res$content)


but I'm getting this error:

Error in httr::content(res$content) : is.response(x) is not TRUE

Any clues?

like image 631
CodingBiology Avatar asked Jan 24 '23 07:01

CodingBiology


2 Answers

After many misadventures, I have your answer as promised!

Since it involves interactive imagery, courtesy of JavaScript and HTML, this solution must be run as a .Rmd file within RStudio. The interactive imagery can also be accessed in the eponymous .html file, output by knitr when you click the Knit button in RStudio.

Step 1: Project Setup

Create a new R project my_pics in RStudio, under a new directory. From within this project, create a new R Notebook (here my_book.Rmd), which should end up right next to my_pics.Rproj under the aforementioned directory.

Step 2: Supporting Files

Under that same directory, create a ./snippets subdirectory. The latter should contain the following two .txt files, copied (and corrected) from the swissbiopics-visualizer documentation:

  • templates.txt: the first code block given in the documentation. Reproduced here with necessary EOF and syntactically corrected comments:
<template id="sibSwissBioPicsStyle">
    <style>
        ul > li > a {
            font-style:oblique;
        }
        ul.notpresent li > .subcell_description {
            display:none;
        }
    </style>
</template>
<template id="sibSwissBioPicsSlLiItem">
    <li class="subcellular_location">
         <a class="subcell_name"></a> <!-- the class name is required and textContent will be set on it -->
         <span class="subcell_description"></span> <!-- the class name is required and textContent will be set on it -->
    </li>
</template>

  • custom_element.txt: the third code block given in the documentation. Reproduced here with necessary EOF:
<script type="module" src="https://www.swissbiopics.org/static/swissbiopics.js"></script>
<script defer>
    if (! window.customElements.get("sib-swissbiopics-sl"))
        window.customElements.define("sib-swissbiopics-sl", SwissBioPicsSL);
</script>

Mind you, these .txt files can just as easily be saved as .html files. Only the file extensions would need to be refactored, in the default values for the templates and custom_element parameters, for the make_html() function in the my_book.Rmd code below.

Step 3: Interact in RStudio

Now we are ready! In my_book.Rmd, write the following:

---
title: "R Notebook"
output: html_document
---


```{r}
library(htmltools)
library(readr)
library(rlang)
```



# Functions #

Here are the functions that do the trick.  The snippets used by `make_html()` are copied from the [documentation](https://www.npmjs.com/package/%40swissprot/swissbiopics-visualizer#usage) for `swissbiopics-visualizer`, and (after fixing the HTML comments) pasted into `.txt` files (`templates.txt` and `custom_element.txt`) under the `./snippets` subdirectory, which lies within the directory containing this `.Rproj`.

```{r}
# Create comma-separated list from vectorized (or listed) items, safely escaped.
csl <- function(items) {
  return(paste("\"", paste(htmltools::htmlEscape(unlist(items)), collapse = ",", sep = ""), "\"", sep = ""))
}



# Create the HTML for the interactive imagery given by the parameters. Assembly
# process is as described the documentation for 'swissbiopics-visualizer':
#   https://www.npmjs.com/package/%40swissprot/swissbiopics-visualizer#usage
make_html <- function(# The NCBI taxonomy ID.
                      tax_id,
                      
                      # The IDs of the cellular elements to highlight.
                      sl_ids,
                      
                      # The filepath to (or raw HTML text of) the templates
                      # snippet.
                      templates = "./snippets/templates.txt",
                      
                      # The filepath to (or raw HTML text of) the custom element
                      # snippet.
                      custom_element = "./snippets/custom_element.txt",
                      
                      # Further arguments to 'readr::read_file()', which might
                      # be useful to process snippet encodings across platforms.
                      ...) {
  # Escape any strings supplied.
  tax_id <- csl(tax_id[1])
  sl_ids <- csl(sl_ids)
  
  
  # Compile all the HTML snippets into a list:
  elements <- list()
  
  
  # Include the templates (as read)...
  elements$templates <- readr::read_file(file = templates, ...)
  
  
  # ...then include the line (created here) to target the right picture...
  elements$identifier <- "<sib-swissbiopics-sl taxid=%s sls=%s></sib-swissbiopics-sl>"
  elements$identifier <- sprintf(fmt = elements$identifier, tax_id, sl_ids)
  
  
  # ...and finally include the definition (as read) for the custom element.
  elements$custom_element <- readr::read_file(file = custom_element, ...)
  
  
  # Append these snippets together, into the full HTML code.
  return(paste(unlist(elements), collapse = "\n"))
}



# Display the interactive imagery given by the parameters, visible in both
# RStudio (crowded) and the R Markdown file (well laid out).
visualize <- function(# The NCBI taxonomy ID.
                      taxid = "9606",
                      
                      # A list (or vector) of the UniProtKB subcellular location
                      # (SL) IDs for the cellular elements to highlight.
                      sls = list("SL0073"),
                      
                      # Further arguments to 'make_html()'.
                      ...
                      ) {
  # Embed the HTML text where this function is called.
  return(htmltools::HTML(make_html(tax_id = taxid, sl_ids = sls, ...)))
}
```



# Results #

Here we `visualize()` the **interactive** image, also accessible on [SwissBioPics](https://www.swissbiopics.org):

```{r}
visualize(sls = list("SL0073", "SL0138"))
```

Note

Observe how (in this case) we "lazily" use the default value ("9606") for taxid, without having to specify it. Observe also how we can simultaneously highlight not one but multiple separate components, namely the Contractile vacuole ("SL0073") and the Cell cortex ("SL0138").


Now below that last chunk where visualize() is called

```{r}
visualize(sls = list("SL0073", "SL0138"))
```

you will see interactive output that looks like this:

enter image description here

Sadly, it appears extremely crowded in RStudio, and an HTML wizard might be needed to alter the supporting .txt (or .html) files, to achieve properly formatted HTML within this IDE.

Step 4: Embed in Reports

As with any .Rmd file, RStudio gives you the option to Knit the Markdown results into a .html file, which can be easily accessed and beautifully formatted as a report!

With my_book.Rmd open in RStudio, click the Knit button, and my_book.html should appear within that same directory. You can open this .html file in a web browser (I used Chrome) to see it in all its glory!

enter image description here

In Conclusion

With either of these two interactive images, you can hover to highlight the various components and layers of the diagram. Furthermore, clicking on any definition will take you by hyperlink to its profile on UnitProt.

Many of the remaining limitations are due to the swissbiopics-visualizer API itself. For example, there seems to be a malfunction in its mapping from GO IDs to SL IDs, via this dataset. As such, you should provide only SL codes to visualize().

That said, if you can wrangle that HTML and bend its layout to your will, the sky is the limit!

Enjoy!


Bonus

Here's a demo of the same interactive output, embedded right here in Stack Overflow! Unfortunately, it's unstable and horribly unwieldy in this environment, so I've left it as a mere "footnote":

<template id="sibSwissBioPicsStyle">
    <style>
        ul > li > a {
            font-style:oblique;
        }
        ul.notpresent li > .subcell_description {
            display:none;
        }
    </style>
</template>
<template id="sibSwissBioPicsSlLiItem">
    <li class="subcellular_location">
         <a class="subcell_name"></a> <!-- the class name is required and textContent will be set on it -->
         <span class="subcell_description"></span> <!-- the class name is required and textContent will be set on it -->
    </li>
</template>


<sib-swissbiopics-sl taxid="9606" sls="SL0073,SL0138" ></sib-swissbiopics-sl>


<script type="module" src="https://www.swissbiopics.org/static/swissbiopics.js"></script>
<script defer>
    if (! window.customElements.get("sib-swissbiopics-sl"))
        window.customElements.define("sib-swissbiopics-sl", SwissBioPicsSL);
</script>
like image 153
Greg Avatar answered Jan 29 '23 01:01

Greg


You have to call the content-function on res, not res$content. Then you get raw content which needs to be converted e.g. via

base::rawToChar(content(res))

which results in a string containing some JS-code

base::rawToChar(content(res))
[1] "var SwissBioPics;SwissBioPics=(()=>....
like image 31
Jonas Avatar answered Jan 29 '23 01:01

Jonas