From 7f70a0c90b1c0cba085f8b61e4252558bc72612c Mon Sep 17 00:00:00 2001 From: Elias Projahn Date: Sun, 11 Dec 2022 19:08:22 +0100 Subject: [PATCH] Add API using plumber --- DESCRIPTION | 2 + NAMESPACE | 1 + R/app.R | 20 ++++++ inst/plumber/ubigen/plumber.R | 129 ++++++++++++++++++++++++++++++++++ man/run_api.Rd | 16 +++++ 5 files changed, 168 insertions(+) create mode 100644 inst/plumber/ubigen/plumber.R create mode 100644 man/run_api.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 10256d1..33cd790 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -33,5 +33,7 @@ Suggests: biomaRt, edgeR, here, + jsonlite, + plumber, purrr, stringr diff --git a/NAMESPACE b/NAMESPACE index 9233be5..50d97a0 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -4,6 +4,7 @@ export(analyze) export(box_plot) export(overview_plot) export(rank_genes) +export(run_api) export(run_app) export(scores_plot) import(data.table) diff --git a/R/app.R b/R/app.R index 3656dfa..eab618b 100644 --- a/R/app.R +++ b/R/app.R @@ -18,3 +18,23 @@ run_app <- function(host = "127.0.0.1", port = port ) } + +#' Run the Ubigen API. +#' +#' This requires the `plumber` package to be installed. +#' +#' @param host The hostname to serve the API on. +#' @param port The port to serve the API on. +#' +#' @export +run_api <- function(host = "127.0.0.1", port = 3465) { + if (!requireNamespace("plumber", quietly = TRUE)) { + stop("Please install \"plumber\" to use this function.") + } + + plumber::plumb(file = system.file( + "plumber", "ubigen", "plumber.R", + package = "ubigen" + )) |> + plumber::pr_run(host = host, port = port, docs = FALSE) +} diff --git a/inst/plumber/ubigen/plumber.R b/inst/plumber/ubigen/plumber.R new file mode 100644 index 0000000..3f43419 --- /dev/null +++ b/inst/plumber/ubigen/plumber.R @@ -0,0 +1,129 @@ +# This file contains an API specification for Ubigen that can be served using +# the `plumber` package. + +library(data.table) +library(plumber) + +#' Retrieve a ranking of genes based on their ubiquity. +#' +#' Provide a whitespace separated list of gene IDs as the request content to +#' filter the results based on these genes. +#' +#' @param dataset The predefined dataset to use. This may be one of +#' `gtex_all`, `gtex_tissues` or `hpa_tissues`. +#' +#' @get /ranking +#' @post /ranking +#' @parser text +#' @serializer csv +ranking <- function(req, + dataset = "gtex_all", + cross_sample_metric = "above_95", + cross_sample_weight = 0.5, + level_metric = "median_expression_normalized", + level_weight = 0.25, + variation_metric = "qcv_expression_normalized", + variation_weight = -0.25) { + ranking <- ubigen::rank_genes( + data = { + analysis <- if (dataset == "gtex_tissues") { + ubigen::gtex_tissues + } else if (dataset == "hpa_tissues") { + ubigen::hpa_tissues + } else { + ubigen::gtex_all + } + + merge(analysis, ubigen::genes, by = "gene") + }, + cross_sample_metric = cross_sample_metric, + cross_sample_weight = as.numeric(cross_sample_weight), + level_metric = level_metric, + level_weight = as.numeric(level_weight), + variation_metric = variation_metric, + variation_weight = as.numeric(variation_weight) + ) + + if (length(req$body) >= 1) { + inputs <- unique(strsplit(req$body, "\\s+")[[1]]) + inputs <- inputs[inputs != ""] + ranking[gene %chin% inputs] + } else { + ranking + } +} + +#' Get a summary of the ubiquity of a given gene set. +#' +#' Provide a whitespace separated list of gene IDs as the request content to +#' analyze these genes. +#' +#' @param dataset The predefined dataset to use. This may be one of +#' `gtex_all`, `gtex_tissues` or `hpa_tissues`. +#' +#' @post /summary +#' @parser text +#' @serializer json +summary <- function(req, + res, + dataset = "gtex_all", + cross_sample_metric = "above_95", + cross_sample_weight = 0.5, + level_metric = "median_expression_normalized", + level_weight = 0.25, + variation_metric = "qcv_expression_normalized", + variation_weight = -0.25) { + ranking <- ubigen::rank_genes( + data = { + analysis <- if (dataset == "gtex_tissues") { + ubigen::gtex_tissues + } else if (dataset == "hpa_tissues") { + ubigen::hpa_tissues + } else { + ubigen::gtex_all + } + + merge(analysis, ubigen::genes, by = "gene") + }, + cross_sample_metric = cross_sample_metric, + cross_sample_weight = as.numeric(cross_sample_weight), + level_metric = level_metric, + level_weight = as.numeric(level_weight), + variation_metric = variation_metric, + variation_weight = as.numeric(variation_weight) + ) + + if (length(req$body) >= 1) { + inputs <- unique(strsplit(req$body, "\\s+")[[1]]) + inputs <- inputs[inputs != ""] + + reference_scores <- ranking[!gene %chin% inputs, score] + comparison_score <- ranking[gene %chin% inputs, score] + comparison_percentile <- ranking[gene %chin% inputs, percentile] + + test_result <- stats::wilcox.test( + x = comparison_score, + y = reference_scores, + conf.int = TRUE + ) + + list( + "median_percentile" = stats::median(comparison_percentile) |> + jsonlite::unbox(), + "median_score" = stats::median(comparison_score) |> + jsonlite::unbox(), + "median_score_reference" = stats::median(reference_scores) |> + jsonlite::unbox(), + "p_value" = test_result$p.value |> jsonlite::unbox(), + "change" = test_result$estimate |> jsonlite::unbox(), + "conf_int_lower" = test_result$conf.int[1] |> jsonlite::unbox(), + "conf_int_upper" = test_result$conf.int[2] |> jsonlite::unbox() + ) + } else { + res$status <- 400 + paste0( + "Please provide a whitespace separated list of Ensembl gene IDs ", + "in the request body." + ) |> jsonlite::unbox() + } +} diff --git a/man/run_api.Rd b/man/run_api.Rd new file mode 100644 index 0000000..40cbff3 --- /dev/null +++ b/man/run_api.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/app.R +\name{run_api} +\alias{run_api} +\title{Run the Ubigen API.} +\usage{ +run_api(host = "127.0.0.1", port = 3465) +} +\arguments{ +\item{host}{The hostname to serve the API on.} + +\item{port}{The port to serve the API on.} +} +\description{ +This requires the \code{plumber} package to be installed. +}