view anndata_operations.xml @ 18:e4bb4666449e draft

"planemo upload for repository https://github.com/ebi-gene-expression-group/container-galaxy-sc-tertiary/tree/develop/tools/tertiary-analysis/scanpy commit 858a2398f1dbbd60110867c593c237358c794615-dirty"
author ebi-gxa
date Mon, 12 Apr 2021 14:40:23 +0000
parents c09d61ede252
children 53a251c6d991
line wrap: on
line source

<?xml version="1.0" encoding="utf-8"?>
<tool id="anndata_ops" name="AnnData Operations" version="@TOOL_VERSION@+galaxy0" profile="@PROFILE@">
  <description>modifies metadata and flags genes</description>
  <macros>
    <import>scanpy_macros2.xml</import>
  </macros>
  <expand macro="requirements"/>
  <command detect_errors="exit_code"><![CDATA[
ln -s '${input_obj_file}' input.h5 &&

#if $copy_o.default:
#for $i, $os in enumerate($copy_o.obs_sources):
  ln -s '${os}' obs_source_${i}.h5 &&
#end for
#end if

#if $copy_e.default:
#for $i, $es in enumerate($copy_e.embedding_sources):
  ln -s '${es}' embedding_source_${i}.h5 &&
#end for
#end if

#if $copy_u.default:
#for $i, $us in enumerate($copy_u.uns_sources):
  ln -s '${us}' uns_source_${i}.h5 &&
#end for
#end if
python $operations
]]></command>
  <configfiles>
    <configfile name="operations">
import scanpy as sc
import anndata
from numpy import all
import logging

adata = sc.read('input.h5')

#if $copy_adata_to_raw:
adata.raw = adata
#end if

gene_name = '${gene_symbols_field}'
qc_vars = list()

#for $i, $s in enumerate($modifications)
adata.obs['${s.to_obs}'] = adata.obs['${s.from_obs}']
#if not $s.keep_original:
del adata.obs['${s.from_obs}']
#end if
#end for

gene_names = getattr(adata.var, gene_name)

#for $i, $flag in enumerate($gene_flags)
k_cat = gene_names.str.startswith('${flag.startswith}')
if k_cat.sum() > 0:
    adata.var['${flag.flag}'] = k_cat
    qc_vars.append('${flag.flag}')
else:
    logging.warning('No genes starting with {} found, skip calculating expression of {} genes'.format('${flag.startswith}', '${flag.flag}'))
#end for

#if $copy_o.default and len($copy_o.obs_keys) > 0:
#for $i, $obs_s in enumerate($copy_o.obs_sources):
ad_s = sc.read('obs_source_${i}.h5')
if adata.n_obs == ad_s.n_obs and all(adata.obs_names == ad_s.obs_names):
  #for $j, $o_key in enumerate($copy_o.obs_keys):
  keys_to_copy = (k for k in ad_s.obs.keys() if "${o_key.contains}" in k)
  for k_to_copy in keys_to_copy:
    suffix=''
    if k_to_copy in adata.obs:
        suffix = "_${i}" 
    
    adata.obs[[k_to_copy+suffix]] = ad_s.obs[[k_to_copy]]
    if k_to_copy in ad_s.uns.keys():
      adata.uns[k_to_copy+suffix] = ad_s.uns[k_to_copy]
  #end for
else:
  logging.warning("Observation source ${i} AnnData file is not compatible to be merged to main AnnData file, different cell names.")
#end for
#end if


#if $copy_e.default and len($copy_e.embedding_keys) > 0:
#for $i, $obs_s in enumerate($copy_e.embedding_sources):
ad_s = sc.read('embedding_source_${i}.h5')
if adata.n_obs == ad_s.n_obs and all(adata.obs_names == ad_s.obs_names):
  #for $j, $e_key in enumerate($copy_e.embedding_keys):
  keys_to_copy = (k for k in ad_s.obsm.keys() if "${e_key.contains}" in k)
  for k_to_copy in keys_to_copy:
    suffix = ''
    if k_to_copy in adata.obsm:
        suffix = "_${i}"
    adata.obsm[k_to_copy+suffix] = ad_s.obsm[k_to_copy]
  #end for
else:
  logging.warning("Embedding source ${i} AnnData file is not compatible to be merged to main AnnData file, different cell names.")
#end for
#end if

#if $copy_u.default and len($copy_u.uns_keys) > 0:
#for $i, $uns_s in enumerate($copy_u.uns_sources):
ad_s = sc.read('uns_source_${i}.h5')
if adata.n_obs == ad_s.n_obs and all(adata.obs_names == ad_s.obs_names):
  #for $j, $u_key in enumerate($copy_u.uns_keys):
  keys_to_copy = (k for k in ad_s.uns.keys() if "${u_key.contains}" in k)
  for k_to_copy in keys_to_copy:
    suffix=''
    if k_to_copy in adata.uns:
        suffix="_${i}"
    adata.uns[k_to_copy+suffix] = ad_s.uns[k_to_copy]
  #end for
else:
  logging.warning("Uns source ${i} AnnData file is not compatible to be merged to main AnnData file, different cell names.")
#end for
#end if

#if $sanitize_varm:
if hasattr(adata, 'raw') and  hasattr(adata.raw, 'X') and hasattr(adata.raw, 'var'):
  new_ad = anndata.AnnData(X=adata.raw.X, obs=adata.obs, var=adata.raw.var)
  adata.raw = new_ad
#end if

if len(qc_vars) > 0:
    pct_top = [${top_genes}]
    sc.pp.calculate_qc_metrics(adata, qc_vars=qc_vars, percent_top=pct_top, inplace=True)

if 'n_genes' not in adata.obs.columns:
    sc.pp.filter_cells(adata, min_genes=0)
if 'n_counts' not in adata.obs.columns:
    sc.pp.filter_cells(adata, min_counts=0)
if 'n_cells' not in adata.var.columns:
    sc.pp.filter_genes(adata, min_cells=0)
if 'n_counts' not in adata.var.columns:
    sc.pp.filter_genes(adata, min_counts=0)

adata.write('output.h5', compression='gzip')
    </configfile>
</configfiles>

  <inputs>
    <param name="input_obj_file" argument="input-object-file" type="data" format="h5,h5ad" label="Input object in hdf5 AnnData format"/>
    <expand macro="output_object_params_no_loom"/>
    <param name="copy_adata_to_raw" type="boolean" label="Copy AnnData to .raw" help="If activated, it will do 'adata.raw = adata'" checked="false"/>
    <repeat name="modifications" title="Change field names in AnnData observations" min="0">
      <param name="from_obs" type="text" label="Original name" help="Name in observations that you want to change">
        <sanitizer>
          <valid initial="string.printable"/>
        </sanitizer>
      </param>
      <param name="to_obs" type="text" label="New name" help="New name in observations that you want to change"/>
      <param name="keep_original" type="boolean" label="Keep original" help="If activated, it will also keep the original column" checked="false"/>
    </repeat>
    <param name="gene_symbols_field" value='index' type="text" label="Gene symbols field in AnnData" help="Field inside var.params where the gene symbols are, normally 'index' or 'gene_symbols'"/>
    <repeat name="gene_flags" title="Flag genes that start with these names">
      <param name="startswith" type="text" label="Starts with" help="Text that you expect the genes to be flagged to start with, such as 'MT-' for mito genes"/>
      <param name="flag" type="text" label="Var name" help="Name of the column in var.names where this boolean flag is stored, for example 'mito' for mitochondrial genes."/>
    </repeat>
    <param name="top_genes" label="Number of top genes" value='50' help="to calculate percentage of the flagged genes in that number of top genes. Used by sc.pp.calculate_qc_metrics (integer)." type="integer"/>
    <conditional name="copy_o">
      <param name="default" type="boolean" checked="false" label="Copy observations (such as clusters)"/>
      <when value="true">
        <repeat name="obs_keys" title="Keys from obs to copy" help="will copy all obs keys in the given AnnData object to the main AnnData object. Make sure to use AnnData objects that are compatible in terms of genes, cells and expression data. You can use this to copy clusters. Uns elements with the same name will be also transferred." min="1">
          <param name="contains" type="text" label="Key contains" help="Keys to be copied need to contain the text set here."/>
        </repeat>
        <param name="obs_sources" type="data" label="AnnData objects with obs to copy" help="Extracts obs (such as clusters) from these AnnData objects and merges them into the main input. Make sure to use AnnData objects that are compatible in terms of genes, cells and expression data." format="h5,h5ad" multiple="true"/>
        <!-- <param name="check_o" type="boolean" label="Check compatibility" help="checks if the provided AnnData objects are compatible (same genes and cells) for merging." checked="true"/> -->
      </when>
      <when value="false"/>
    </conditional>
    <conditional name="copy_e">
      <param name="default" type="boolean" checked="false" label="Copy embeddings (such as UMAP, tSNE)"/>
      <when value="true">
        <repeat name="embedding_keys" title="Keys from embeddings to copy" help="will copy all embedding keys in the given AnnData object to the main AnnData object. Make sure to use AnnData objects that are compatible in terms of genes, cells and expression data. You can use this to copy tSNE, UMAP, etc." min="1">
          <param name="contains" type="text" label="Key contains" help="Keys to be copied need to contain the text set here."/>
        </repeat>
        <param name="embedding_sources" type="data" label="AnnData objects with embeddings to copy" help="Extracts embeddings (tSNE, UMAP) from these AnnData objects and merges them into the main input. Make sure to use AnnData objects that are compatible in terms of genes, cells and expression data." format="h5,h5ad" multiple="true"/>
        <!-- <param name="check_e" type="boolean" label="Check compatibility" help="checks if the provided AnnData objects are compatible (same genes and cells) for merging." checked="true"/> -->
      </when>
      <when value="false"/>
    </conditional>
    <conditional name="copy_u">
      <param name="default" type="boolean" checked="false" label="Copy uns"/>
      <when value="true">
        <repeat name="uns_keys" title="Keys from uns to copy" help="will copy all uns keys in the given AnnData object to the main AnnData object. Make sure to use AnnData objects that are compatible in terms of genes, cells and expression data. You can use this to copy rank_genes_groups for instance." min="1">
          <param name="contains" type="text" label="Key contains" help="Keys to be copied need to contain the text set here."/>
        </repeat>
        <param name="uns_sources" type="data" label="AnnData objects with uns to copy" help="Extracts uns (such as ranked_genes_groups) from these AnnData objects and merges them into the main input. Make sure to use AnnData objects that are compatible in terms of genes, cells and expression data." format="h5,h5ad" multiple="true"/>
      </when>
    </conditional>
    <param name="sanitize_varm" type="boolean" checked="false" label="Sanitise any null raw.varm objects if any" help="This might be relevant for interfacing with newer versions of AnnData, that might complain if .raw includes a varm null object."/>
  </inputs>

  <outputs>
    <expand macro="output_data_obj_no_loom" description="metadata changes on"/>
  </outputs>

  <tests>
    <test>
      <param name="input_obj_file" value="find_cluster.h5"/>
      <param name="input_format" value="anndata"/>
      <param name="color_by" value="louvain"/>
      <output name="output_h5ad" file="anndata_ops.h5" ftype="h5ad" compare="sim_size"/>
    </test>
  </tests>

  <help><![CDATA[
=============================
Operations on AnnData objects
=============================

Performs the following operations:

* Change observation fields, mostly for downstreaming processes convenience. Multiple fields can be changed as one.
* Flag genes that start with a certain text: useful for flagging mitochondrial, spikes or other groups of genes.
* For the flags created, calculates qc metrics (pct_<flag>_counts).
* Calculates `n_genes`, `n_counts` for cells and `n_cells`, `n_counts` for genes.
* For top <N> genes specified, calculate qc metrics (pct_counts_in_top_<N>_genes).
* Copy from a set of compatible AnnData objects (same cells and genes):
  * Observations, such as clustering results.
  * Embeddings, such as tSNE or UMAPs.
  * Unstructure annotations, like gene markers.

This functionality will probably be added in the future to a larger package.

History
-------

1.6.0+galaxy0: Moves to Scanpy Scripts 0.3.0 (Scanpy 1.6.0), versioning switched to track Scanpy as other tools.

0.0.3+galaxy0: Adds ability to merge AnnData objects (Scanpy 1.4.3).
]]></help>
  <expand macro="citations"/>
</tool>