Skip to content

Commit

Permalink
feat: Enhanced-volcano (#1521)
Browse files Browse the repository at this point in the history
<!-- Ensure that the PR title follows conventional commit style (<type>:
<description>)-->
<!-- Possible types are here:
https://github.com/commitizen/conventional-commit-types/blob/master/index.json
-->

### Description

This PR adds
[EnhancedVolcano](https://bioconductor.org/packages/3.17/bioc/html/EnhancedVolcano.html)
to the list of available wrappers

### QC
<!-- Make sure that you can tick the boxes below. -->

* [x] I confirm that:

For all wrappers added by this PR, 

* there is a test case which covers any introduced changes,
* `input:` and `output:` file paths in the resulting rule can be changed
arbitrarily,
* either the wrapper can only use a single core, or the example rule
contains a `threads: x` statement with `x` being a reasonable default,
* rule names in the test case are in
[snake_case](https://en.wikipedia.org/wiki/Snake_case) and somehow tell
what the rule is about or match the tools purpose or name (e.g.,
`map_reads` for a step that maps reads),
* all `environment.yaml` specifications follow [the respective best
practices](https://stackoverflow.com/a/64594513/2352071),
* wherever possible, command line arguments are inferred and set
automatically (e.g. based on file extensions in `input:` or `output:`),
* all fields of the example rules in the `Snakefile`s and their entries
are explained via comments (`input:`/`output:`/`params:` etc.),
* `stderr` and/or `stdout` are logged correctly (`log:`), depending on
the wrapped tool,
* temporary files are either written to a unique hidden folder in the
working directory, or (better) stored where the Python function
`tempfile.gettempdir()` points to (see
[here](https://docs.python.org/3/library/tempfile.html#tempfile.gettempdir);
this also means that using any Python `tempfile` default behavior
works),
* the `meta.yaml` contains a link to the documentation of the respective
tool or command,
* `Snakefile`s pass the linting (`snakemake --lint`),
* `Snakefile`s are formatted with
[snakefmt](https://github.com/snakemake/snakefmt),
* Python wrapper scripts are formatted with
[black](https://black.readthedocs.io).
* Conda environments use a minimal amount of channels, in recommended
ordering. E.g. for bioconda, use (conda-forge, bioconda, nodefaults, as
conda-forge should have highest priority and defaults channels are
usually not needed because most packages are in conda-forge nowadays).

---------

Co-authored-by: tdayris <tdayris@gustaveroussy.fr>
Co-authored-by: tdayris <thibault.dayris@gustaveroussy.fr>
Co-authored-by: Johannes Köster <johannes.koester@uni-due.de>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: snakedeploy-bot[bot] <115615832+snakedeploy-bot[bot]@users.noreply.github.com>
Co-authored-by: Felix Mölder <felix.moelder@uni-due.de>
Co-authored-by: Christopher Schröder <christopher.schroeder@tu-dortmund.de>
  • Loading branch information
8 people committed Aug 25, 2023
1 parent e35e312 commit 0bd316d
Show file tree
Hide file tree
Showing 8 changed files with 224 additions and 0 deletions.
6 changes: 6 additions & 0 deletions bio/enhancedvolcano/environment.yaml
@@ -0,0 +1,6 @@
channels:
- conda-forge
- bioconda
- nodefaults
dependencies:
- bioconductor-enhancedvolcano =1.18.0
16 changes: 16 additions & 0 deletions bio/enhancedvolcano/meta.yaml
@@ -0,0 +1,16 @@
name: Enhanced Volcano
url: https://bioconductor.org/packages/3.17/bioc/html/EnhancedVolcano.html
authors:
- Thibault Dayris
description: |
Build Volcano-plots with EnhancedVolcano
input:
- Path to a TSV/CSV table (separator are inferred from file extension) or a RDS formatted object convertible into a `data.frame`.
output:
- Path to SVG or PNG formatted Volcano plot
params:
- extra: additional parameters besides `toptable`
- height: plot default height (in `grDevices::svg`)
- width: plot default width (in `grDevices::svg`)
notes: |
* Input table requires at least the following: column for variable names; a column for log2 fold changes; a column for nominal or adjusted p-value.
46 changes: 46 additions & 0 deletions bio/enhancedvolcano/test/Snakefile
@@ -0,0 +1,46 @@
rule test_enhanced_volcano_tsv:
input:
"table.tsv",
output:
"volcano_tsv.png",
threads: 1
log:
"logs/enhanced-volcano/tsv.log",
params:
extra="lab='Gene_id', x='ShrinkedFC', y='adjusted_pvalues'",
width=1024, # Optional PNG width
height=768, # Optional PNG height
wrapper:
"master/bio/enhancedvolcano"


rule test_enhanced_volcano_csv:
input:
"table.csv",
output:
"volcano_csv.svg",
threads: 1
log:
"logs/enhanced-volcano/csv.log",
params:
extra="lab='Gene_id', x='ShrinkedFC', y='adjusted_pvalues'",
# width=7, # Optional PNG width
# height=7, # Optional PNG height
wrapper:
"master/bio/enhancedvolcano"


rule test_enhanced_volcano_rds:
input:
"table.RDS",
output:
"volcano_rds.svg",
threads: 1
log:
"logs/enhanced-volcano/rds.log",
params:
extra="lab='Gene_id', x='ShrinkedFC', y='adjusted_pvalues'",
# width=7, # Optional PNG width
# height=7, # Optional PNG height
wrapper:
"master/bio/enhancedvolcano"
Binary file added bio/enhancedvolcano/test/table.RDS
Binary file not shown.
5 changes: 5 additions & 0 deletions bio/enhancedvolcano/test/table.csv
@@ -0,0 +1,5 @@
Gene_id,ShrinkedFC,adjusted_pvalues
G1,12.05,0.006
G2,0,1
G3,17,0.7
G4,0.01,0.003
5 changes: 5 additions & 0 deletions bio/enhancedvolcano/test/table.tsv
@@ -0,0 +1,5 @@
Gene_id ShrinkedFC adjusted_pvalues
G1 12.05 0.006
G2 0 1
G3 17 0.7
G4 0.01 0.003
110 changes: 110 additions & 0 deletions bio/enhancedvolcano/wrapper.R
@@ -0,0 +1,110 @@
# __author__ = "Thibault Dayris"
# __copyright__ = "Copyright 2023, Thibault Dayris"
# __email__ = "thibault.dayris@gustaveroussy.fr"
# __license__ = "MIT"

# This script builds a Volcano plot from a table or
# a RDS object that can be casted into a data.frame

# Sink the stderr and stdout to the snakemake log file
# https://stackoverflow.com/a/48173272
log.file <- base::file(snakemake@log[[1]], open = "wt")
base::sink(log.file)
base::sink(log.file, type = "message")

# Loading Libraries and input data
base::library(package = "EnhancedVolcano", character.only = TRUE)
base::message("Library loaded")

save_png <- function(output_path, width, height) {
grDevices::png(
filename = output_path,
width = width,
height = height,
)

base::print(base::eval(base::parse(text = cmd)))

grDevices::dev.off()
}

save_svg <- function(output_path, width, height) {
grDevices::svg(
filename = output_path,
width = width,
height = height
)

base::print(base::eval(base::parse(text = cmd)))

grDevices::dev.off()
}

input_path <- base::as.character(x = snakemake@input[[1]])
toptable <- NULL
if (base::endsWith(x = input_path, suffix = ".tsv")) {
toptable <- utils::read.table(
file = input_path,
header = TRUE,
sep = "\t",
stringsAsFactors = FALSE,
)
} else if (base::endsWith(x = input_path, suffix = ".csv")) {
toptable <- utils::read.table(
file = input_path,
header = TRUE,
sep = ",",
stringsAsFactors = FALSE,
)
} else if (base::endsWith(x = input_path, suffix = ".RDS")) {
toptable <- base::readRDS(file = input_path)
} else {
base::stop(
"Input file format unknown. Expected either '.tsv', '.csv', or 'RDS'"
)
}
base::message("Data loaded")
base::print(toptable)

# Building command line
extra <- "toptable = toptable"
if ("extra" %in% base::names(snakemake@params)) {
extra <- base::paste(
extra,
base::as.character(x = snakemake@params[["extra"]]),
sep = ","
)
}

width <- 7
if ("width" %in% base::names(snakemake@params)) {
width <- base::as.numeric(x = snakemake@params[["width"]])
}
height <- 7
if ("height" %in% base::names(snakemake@params)) {
height <- base::as.numeric(x = snakemake@params[["height"]])
}


cmd <- base::paste0(
"EnhancedVolcano::EnhancedVolcano(",
extra,
")"
)
base::message("Command line: ")
base::message(cmd)


# Run EnhancedVolcano
outfile <- base::as.character(x = snakemake@output[[1]])
if (base::endsWith(x = outfile, suffix = ".png")) {
save_png(output_path = outfile, width = width, height = height)
} else {
save_svg(output_path = outfile, width = width, height = height)
}
base::message("Process over")

# Proper syntax to close the connection for the log file
# but could be optional for Snakemake wrapper
base::sink(type = "message")
base::sink()
36 changes: 36 additions & 0 deletions test.py
Expand Up @@ -1181,6 +1181,42 @@ def test_bwa_mapping_meta():
)


@skip_if_not_modified
def test_enhanced_volcano():
run(
"bio/enhancedvolcano",
[
"snakemake",
"--cores",
"1",
"--use-conda",
"volcano_tsv.png",
],
)

run(
"bio/enhancedvolcano",
[
"snakemake",
"--cores",
"1",
"--use-conda",
"volcano_csv.svg",
],
)

run(
"bio/enhancedvolcano",
[
"snakemake",
"--cores",
"1",
"--use-conda",
"volcano_rds.svg",
],
)


@skip_if_not_modified
def test_gridss_call():
run(
Expand Down

0 comments on commit 0bd316d

Please sign in to comment.