<?xml version="1.0" encoding="UTF-8"?>
<TEI xmlns="http://www.tei-c.org/ns/1.0" xml:lang="en">
  <teiHeader>
    <fileDesc>
      <titleStmt>
        <title>SCANPY: large-scale single-cell gene expression data analysis</title>
        <author>F. Alexander Wolf</author>
        <author>Philipp Angerer</author>
        <author>Fabian J. Theis</author>
      </titleStmt>
      <publicationStmt>
        <p>Tag layer of the DHSS Meta-Tagging Project. The article text is reproduced from the
           staged copy named in sourceDesc and is not altered; the tags are held separately in
           standOff so that overlapping and nested spans are preserved.</p>
      </publicationStmt>
      <sourceDesc>
        <bibl>
          <title>SCANPY: large-scale single-cell gene expression data analysis</title>
          <date>2018</date>
          <publisher>Genome biology</publisher>
          <idno type="DOI">10.1186/s13059-017-1382-0</idno>
          
          <idno type="record">wolf2018-scanpy-large-scale-single-cell-gen</idno>
          <note type="staged-file">wolf2018-scanpy-large-scale-single-cell-gen.txt, the project's staged copy</note>
          <note type="text-sha1">5308128fbd70ce88c47cd7e1afde42dc09ec050b</note>
          <note type="rights">cc-by</note>
        </bibl>
      </sourceDesc>
    </fileDesc>
    <profileDesc>
      <textClass><keywords><term>biology</term></keywords></textClass>
      <particDesc>
        <person xml:id="paper"><p>the paper's own words</p></person>
        <person xml:id="tagger"><p>the tag layer; a sentence written by the tagger about the
          paper, always anchored to a quotation but not itself a quotation</p></person>
      </particDesc>
    </profileDesc>
    <revisionDesc>
      <change when="2026-10-06"
              who="build_paper_edition.py">87 spans located by searching the stored text for the quote's exact words, allowing any whitespace between them</change>
    </revisionDesc>
  </teiHeader>
  <standOff>
    <spanGrp type="tags">
      <span xml:id="t0" from="#a6" to="#a7" type="object_of_study" ana="#object_of_study" resp="#paper">single-cell gene expression data at a scale existing frameworks do not reach</span>
      <span xml:id="t1" from="#a6" to="#a7" type="research_question" ana="#research_question" resp="#paper">how to give the established single-cell analyses a form that scales past a million cells</span>
      <span xml:id="t2" from="#a15" to="#a16" type="contribution" ana="#contribution" resp="#paper">SCANPY, and ANNDATA - a generic annotated data matrix that every tool reads and writes without changing its structure</span>
      <span xml:id="t3" from="#a6" to="#a7" type="claim_type" ana="#claim_type" resp="#paper">method</span>
      <span xml:id="t4" from="#a6" to="#a7" type="phenomenon" ana="#phenomenon" resp="#paper">analysis frameworks failing at data sizes their science has already reached</span>
      <span xml:id="t5" from="#a30" to="#a31" type="method" ana="#method" resp="#paper">system-or-tool-building<term>system-or-tool-building</term></span>
      <span xml:id="t6" from="#a30" to="#a31" type="mechanisms" ana="#mechanisms[0]" resp="#tagger" cert="0.95">mechanisms<term>ONE REPRESENTATION, COMPUTED ONCE, REUSED: the tools share a single graph of the data instead of each building its own, which the paper justifies by what it avoids - DIFFERENT, POTENTIALLY INCONSISTENT representations of the same data</term></span>
      <span xml:id="t7" from="#a17" to="#a18" type="mechanisms" ana="#mechanisms[1]" resp="#tagger" cert="0.95">mechanisms<term>EXTENSIBILITY THROUGH A FIXED STRUCTURE: a tool extracts from the matrix and writes its result back into the same object, and the object&#x27;s structure is unaffected - so adding a method does not oblige anything else to change</term></span>
      <span xml:id="t8" from="#a21" to="#a23" type="mechanisms" ana="#mechanisms[2]" resp="#tagger" cert="0.95">mechanisms<term>SCALE BY CHANGING RESIDENCY, NOT ALGORITHM: HDF5 backing lets the object be operated on without being loaded, so the limit moves from memory size to disk</term></span>
      <span xml:id="t9" from="#a27" to="#a28" type="mechanisms" ana="#mechanisms[3]" resp="#tagger" cert="0.95">mechanisms<term>SPEED FROM BLOCKING, NOT FROM APPROXIMATION: neighbourhood distances are computed by aggregating rows into submatrices and multiplying, rather than by sampling</term></span>
      <span xml:id="t10" from="#a32" to="#a33" type="limitations" ana="#limitations[0]" resp="#tagger" cert="0.95">The comparison offered is against R-based frameworks and CELL RANGER; the claim of no comparable toolkit is scoped to the PYTHON ecosystem, in the paper&#x27;s own words</span>
      <span xml:id="t11" from="#a13" to="#a14" type="limitations" ana="#limitations[1]" resp="#tagger" cert="0.95">The scaling evidence is a demonstration on named datasets - 68,579 cells for the speedup and 1.3 million for feasibility - not a complexity result</span>
      <span xml:id="t12" from="#a9" to="#a10" type="controls" ana="#controls[0]" resp="#tagger" cert="0.8">benchmarking SCANPY against established single-cell analysis packages on a clustering tutorial of 2,700 peripheral blood mononuclear cells<note>eliminates: that SCANPY&#x27;s clustering results differ from what the established tools produce on the same data, so that its speed advantage comes at a cost in output · outcome: held</note></span>
      <span xml:id="t13" from="#a6" to="#a8" type="concepts" ana="#concepts[0]" resp="#paper" cert="0.95">SCANPY<term>SCANPY</term></span>
      <span xml:id="t14" from="#a15" to="#a16" type="concepts" ana="#concepts[1]" resp="#paper" cert="0.95">ANNDATA<term>ANNDATA</term></span>
      <span xml:id="t15" from="#a19" to="#a20" type="concepts" ana="#concepts[2]" resp="#paper" cert="0.95">EXPRESSIONSET<term>EXPRESSIONSET</term></span>
      <span xml:id="t16" from="#a21" to="#a23" type="concepts" ana="#concepts[3]" resp="#paper" cert="0.95">backed mode<term>backed mode</term></span>
      <span xml:id="t17" from="#a21" to="#a23" type="concepts" ana="#concepts[4]" resp="#paper" cert="0.95">memory mode<term>memory mode</term></span>
      <span xml:id="t18" from="#a15" to="#a16" type="concepts" ana="#concepts[5]" resp="#paper" cert="0.95">annotations<term>annotations</term></span>
      <span xml:id="t19" from="#a15" to="#a16" type="concepts" ana="#concepts[6]" resp="#paper" cert="0.95">data matrix<term>data matrix</term></span>
      <span xml:id="t20" from="#a27" to="#a28" type="concepts" ana="#concepts[7]" resp="#paper" cert="0.95">neighborhood relations<term>neighborhood relations</term></span>
      <span xml:id="t21" from="#a30" to="#a31" type="concepts" ana="#concepts[8]" resp="#paper" cert="0.95">single graph representation<term>single graph representation</term></span>
      <span xml:id="t22" from="#a19" to="#a20" type="concepts" ana="#concepts[9]" resp="#paper" cert="0.95">sparse data<term>sparse data</term></span>
      <span xml:id="t23" from="#a11" to="#a12" type="concepts" ana="#concepts[10]" resp="#paper" cert="0.95">CELL RANGER<term>CELL RANGER</term></span>
      <span xml:id="t24" from="#a5" to="#a7" type="concepts" ana="#concepts[11]" resp="#paper" cert="0.85">SEURAT<term>SEURAT</term></span>
      <span xml:id="t25" from="#a32" to="#a33" type="concepts" ana="#concepts[12]" resp="#paper" cert="0.95">Python ecosystem<term>Python ecosystem</term></span>
      <span xml:id="t26" from="#a1" to="#a2" type="concepts" ana="#concepts[13]" resp="#paper" cert="0.95">scalable toolkit<term>scalable toolkit</term></span>
      <span xml:id="t27" from="#a1" to="#a2" type="concepts" ana="#concepts[14]" resp="#paper" cert="0.95">preprocessing<term>preprocessing</term></span>
      <span xml:id="t28" from="#a1" to="#a2" type="concepts" ana="#concepts[15]" resp="#paper" cert="0.95">visualization<term>visualization</term></span>
      <span xml:id="t29" from="#a1" to="#a2" type="concepts" ana="#concepts[16]" resp="#paper" cert="0.95">clustering<term>clustering</term></span>
      <span xml:id="t30" from="#a1" to="#a2" type="concepts" ana="#concepts[17]" resp="#paper" cert="0.95">pseudotime and trajectory inference<term>pseudotime and trajectory inference</term></span>
      <span xml:id="t31" from="#a1" to="#a2" type="concepts" ana="#concepts[18]" resp="#paper" cert="0.95">differential expression testing<term>differential expression testing</term></span>
      <span xml:id="t32" from="#a1" to="#a2" type="concepts" ana="#concepts[19]" resp="#paper" cert="0.95">simulation of gene regulatory networks<term>simulation of gene regulatory networks</term></span>
      <span xml:id="t33" from="#a3" to="#a4" type="concepts" ana="#concepts[20]" resp="#paper" cert="0.95">generic class<term>generic class</term></span>
      <span xml:id="t34" from="#a3" to="#a4" type="concepts" ana="#concepts[21]" resp="#paper" cert="0.95">annotated data matrices<term>annotated data matrices</term></span>
      <span xml:id="t35" from="#a19" to="#a22" type="concepts" ana="#concepts[22]" resp="#paper" cert="0.95">HDF5-based backing<term>HDF5-based backing</term></span>
      <span xml:id="t36" from="#a24" to="#a25" type="concepts" ana="#concepts[23]" resp="#paper" cert="0.95">in-place<term>in-place</term></span>
      <span xml:id="t37" from="#a24" to="#a25" type="concepts" ana="#concepts[24]" resp="#paper" cert="0.95">non-destructive transformation<term>non-destructive transformation</term></span>
      <span xml:id="t38" from="#a24" to="#a25" type="concepts" ana="#concepts[25]" resp="#paper" cert="0.95">online-learning formulations<term>online-learning formulations</term></span>
      <span xml:id="t39" from="#a26" to="#a29" type="concepts" ana="#concepts[26]" resp="#paper" cert="0.95">class for representing a graph of neighborhood relations<term>class for representing a graph of neighborhood relations</term></span>
      <span xml:id="t40" from="#a26" to="#a29" type="concepts" ana="#concepts[27]" resp="#paper" cert="0.95">random-walk-based metrics<term>random-walk-based metrics</term></span>
      <span xml:id="t41" from="#a34" to="#a35" type="concepts" ana="#concepts[28]" resp="#paper" cert="0.95">static<term>static</term></span>
      <span xml:id="t42" from="#a34" to="#a35" type="concepts" ana="#concepts[29]" resp="#paper" cert="0.95">dynamic HDF5 backing<term>dynamic HDF5 backing</term></span>
      <span xml:id="t43" from="#a36" to="#a37" type="concepts" ana="#concepts[30]" resp="#paper" cert="0.95">FLOTILLA<term>FLOTILLA</term></span>
      <span xml:id="t44" from="#a36" to="#a37" type="concepts" ana="#concepts[31]" resp="#paper" cert="0.95">data analysis framework<term>data analysis framework</term></span>
      <span xml:id="t45" from="#a36" to="#a37" type="concepts" ana="#concepts[32]" resp="#paper" cert="0.95">STUDY<term>STUDY</term></span>
      <span xml:id="t46" from="#a36" to="#a37" type="concepts" ana="#concepts[33]" resp="#paper" cert="0.95">simple HDF5-backed class ANNDATA<term>simple HDF5-backed class ANNDATA</term></span>
      <span xml:id="t47" from="#a36" to="#a37" type="concepts" ana="#concepts[34]" resp="#paper" cert="0.95">large-scale data<term>large-scale data</term></span>
      <span xml:id="t48" from="#a36" to="#a37" type="concepts" ana="#concepts[35]" resp="#paper" cert="0.95">graph-based methods<term>graph-based methods</term></span>
      <span xml:id="t49" from="#a34" to="#a35" type="unhoused_relations" ana="#unhoused_relations[0]" resp="#tagger" cert="0.95">static → dynamic HDF5 backing<note>The paper says AnnData&#x27;s HDF5 backing was extended from static to dynamic. A state transition is not one of the eight edge types.</note></span>
      <span xml:id="t50" from="#a15" to="#a16" type="senses" ana="#senses[0]" resp="#tagger" cert="0.95">ANNDATA - THE ANNOTATION IS THE POINT, NOT THE MATRIX: a data matrix plus annotations of observations, of variables, and unstructured ones, held together so a tool can add a result without changing the structure everything else reads</span>
      <span xml:id="t51" from="#a21" to="#a23" type="senses" ana="#senses[1]" resp="#tagger" cert="0.95">backed mode - the same object read WITHOUT being loaded into memory, as opposed to memory mode. One class, two residencies, and the analysis code does not change</span>
      <span xml:id="t52" from="#a1" to="#a2" type="senses" ana="#senses[2]" resp="#tagger" cert="0.95">scalable toolkit - the software class to which the abstract assigns Scanpy</span>
      <span xml:id="t53" from="#a1" to="#a2" type="senses" ana="#senses[3]" resp="#tagger" cert="0.95">preprocessing - one analysis capability included in Scanpy</span>
      <span xml:id="t54" from="#a1" to="#a2" type="senses" ana="#senses[4]" resp="#tagger" cert="0.95">visualization - one analysis capability included in Scanpy</span>
      <span xml:id="t55" from="#a1" to="#a2" type="senses" ana="#senses[5]" resp="#tagger" cert="0.95">clustering - one analysis capability included in Scanpy</span>
      <span xml:id="t56" from="#a1" to="#a2" type="senses" ana="#senses[6]" resp="#tagger" cert="0.95">pseudotime and trajectory inference - temporal and lineage reconstruction capabilities included in Scanpy</span>
      <span xml:id="t57" from="#a1" to="#a2" type="senses" ana="#senses[7]" resp="#tagger" cert="0.95">differential expression testing - one analysis capability included in Scanpy</span>
      <span xml:id="t58" from="#a1" to="#a2" type="senses" ana="#senses[8]" resp="#tagger" cert="0.95">simulation of gene regulatory networks - the network-simulation capability included in Scanpy</span>
      <span xml:id="t59" from="#a3" to="#a4" type="senses" ana="#senses[9]" resp="#tagger" cert="0.95">generic class - the software class assigned to AnnData for handling annotated matrices</span>
      <span xml:id="t60" from="#a3" to="#a4" type="senses" ana="#senses[10]" resp="#tagger" cert="0.95">annotated data matrices - the matrix form handled by the generic AnnData class</span>
      <span xml:id="t61" from="#a19" to="#a22" type="senses" ana="#senses[11]" resp="#tagger" cert="0.95">HDF5-based backing - on-disk backing that permits operating without fully loading an AnnData object</span>
      <span xml:id="t62" from="#a24" to="#a25" type="senses" ana="#senses[12]" resp="#tagger" cert="0.95">in-place - Scanpy&#x27;s default object transformation mode for memory-efficient pipelines</span>
      <span xml:id="t63" from="#a24" to="#a25" type="senses" ana="#senses[13]" resp="#tagger" cert="0.95">non-destructive transformation - the optional alternative to in-place transformation</span>
      <span xml:id="t64" from="#a24" to="#a25" type="senses" ana="#senses[14]" resp="#tagger" cert="0.95">online-learning formulations - algorithm formulations that pipelines can exploit in backed mode</span>
      <span xml:id="t65" from="#a26" to="#a29" type="senses" ana="#senses[15]" resp="#tagger" cert="0.95">class for representing a graph of neighborhood relations - Scanpy&#x27;s representation of neighborhood relations among data points</span>
      <span xml:id="t66" from="#a26" to="#a29" type="senses" ana="#senses[16]" resp="#tagger" cert="0.95">random-walk-based metrics - metrics exposed by Scanpy&#x27;s neighborhood-graph class but absent from other graph software</span>
      <span xml:id="t67" from="#a34" to="#a35" type="senses" ana="#senses[17]" resp="#tagger" cert="0.95">static - AnnData&#x27;s earlier HDF5 backing state</span>
      <span xml:id="t68" from="#a34" to="#a35" type="senses" ana="#senses[18]" resp="#tagger" cert="0.95">dynamic HDF5 backing - the HDF5 backing state to which AnnData was extended</span>
      <span xml:id="t69" from="#a36" to="#a37" type="senses" ana="#senses[19]" resp="#tagger" cert="0.95">FLOTILLA - the other Python framework that solves more than one analysis task</span>
      <span xml:id="t70" from="#a36" to="#a37" type="senses" ana="#senses[20]" resp="#tagger" cert="0.95">data analysis framework - the multi-task software class the paper assigns to FLOTILLA</span>
      <span xml:id="t71" from="#a36" to="#a37" type="senses" ana="#senses[21]" resp="#tagger" cert="0.95">STUDY - FLOTILLA&#x27;s class combining data, tools, and plotting functions</span>
      <span xml:id="t72" from="#a36" to="#a37" type="senses" ana="#senses[22]" resp="#tagger" cert="0.95">simple HDF5-backed class ANNDATA - the contrasting class around which Scanpy is built</span>
      <span xml:id="t73" from="#a36" to="#a37" type="senses" ana="#senses[23]" resp="#tagger" cert="0.95">large-scale data - a target that the paper says FLOTILLA does not address</span>
      <span xml:id="t74" from="#a36" to="#a37" type="senses" ana="#senses[24]" resp="#tagger" cert="0.95">graph-based methods - Scanpy&#x27;s core method family, absent from FLOTILLA</span>
      <span xml:id="t75" from="#a19" to="#a20" type="concept_edges" ana="#concept_edges[0]" resp="#tagger">ANNDATA —contrasted-with→ EXPRESSIONSET<note>differs in: sparse data support and HDF5-based backing on disk, which is what lets an object be operated on without being loaded · strength of the relation: 1
Audit 2026-09-28: DOUBTFUL - read against its full span and kept, but the span calls ANNDATA SIMILAR to EXPRESSIONSET, with differences; contrasted-with is loose.</note><term>ANNDATA</term><term>EXPRESSIONSET</term></span>
      <span xml:id="t76" from="#a17" to="#a18" type="concept_edges" ana="#concept_edges[1]" resp="#tagger">ANNDATA —part-of→ SCANPY<note>strength of the relation: 1
Audit 2026-09-28: DOUBTFUL - read against its full span and kept, but the span says SCANPY is built around the ANNDATA class; part-of is loose.</note><term>ANNDATA</term><term>SCANPY</term></span>
      <span xml:id="t77" from="#a21" to="#a23" type="concept_edges" ana="#concept_edges[2]" resp="#tagger">backed mode —distinct-from→ memory mode<note>strength of the relation: 1</note><term>backed mode</term><term>memory mode</term></span>
      <span xml:id="t78" from="#a1" to="#a2" type="concept_edges" ana="#concept_edges[3]" resp="#tagger" cert="0.95">SCANPY —is-a→ scalable toolkit<note>the relation itself is separately evidenced · strength of the relation: 1 · note: The abstract gives an unhedged class definition.</note><term>SCANPY</term><term>scalable toolkit</term></span>
      <span xml:id="t79" from="#a1" to="#a2" type="concept_edges" ana="#concept_edges[4]" resp="#tagger" cert="0.95">preprocessing —part-of→ SCANPY<note>the relation itself is separately evidenced · strength of the relation: 1 · note: The abstract unhedgedly includes preprocessing among Scanpy&#x27;s methods.</note><term>preprocessing</term><term>SCANPY</term></span>
      <span xml:id="t80" from="#a1" to="#a2" type="concept_edges" ana="#concept_edges[5]" resp="#tagger" cert="0.95">visualization —part-of→ SCANPY<note>the relation itself is separately evidenced · strength of the relation: 1 · note: The abstract unhedgedly includes visualization among Scanpy&#x27;s methods.</note><term>visualization</term><term>SCANPY</term></span>
      <span xml:id="t81" from="#a1" to="#a2" type="concept_edges" ana="#concept_edges[6]" resp="#tagger" cert="0.95">clustering —part-of→ SCANPY<note>the relation itself is separately evidenced · strength of the relation: 1 · note: The abstract unhedgedly includes clustering among Scanpy&#x27;s methods.</note><term>clustering</term><term>SCANPY</term></span>
      <span xml:id="t82" from="#a1" to="#a2" type="concept_edges" ana="#concept_edges[7]" resp="#tagger" cert="0.95">pseudotime and trajectory inference —part-of→ SCANPY<note>the relation itself is separately evidenced · strength of the relation: 1 · note: The abstract unhedgedly includes pseudotime and trajectory inference among Scanpy&#x27;s methods.</note><term>pseudotime and trajectory inference</term><term>SCANPY</term></span>
      <span xml:id="t83" from="#a1" to="#a2" type="concept_edges" ana="#concept_edges[8]" resp="#tagger" cert="0.95">differential expression testing —part-of→ SCANPY<note>the relation itself is separately evidenced · strength of the relation: 1 · note: The abstract unhedgedly includes differential-expression testing among Scanpy&#x27;s methods.</note><term>differential expression testing</term><term>SCANPY</term></span>
      <span xml:id="t84" from="#a1" to="#a2" type="concept_edges" ana="#concept_edges[9]" resp="#tagger" cert="0.95">simulation of gene regulatory networks —part-of→ SCANPY<note>the relation itself is separately evidenced · strength of the relation: 1 · note: The abstract unhedgedly includes regulatory-network simulation among Scanpy&#x27;s methods.</note><term>simulation of gene regulatory networks</term><term>SCANPY</term></span>
      <span xml:id="t85" from="#a36" to="#a37" type="concept_edges" ana="#concept_edges[10]" resp="#tagger" cert="0.95">FLOTILLA —distinct-from→ SCANPY<note>differs in: single-cell and large-scale targeting, graph-based methods, and the complexity of the central data class · the relation itself is separately evidenced · strength of the relation: 1 · note: The paper explicitly says &#x27;in contrast to SCANPY&#x27; and names the dimensions of difference.</note><term>FLOTILLA</term><term>SCANPY</term></span>
      <span xml:id="t86" from="#a36" to="#a37" type="concept_edges" ana="#concept_edges[11]" resp="#tagger" cert="0.95">STUDY —contrasted-with→ simple HDF5-backed class ANNDATA<note>differs in: a complicated class containing data, tools, and plotting functions versus a simple HDF5-backed class · the relation itself is separately evidenced · strength of the relation: 1 · note: The paper&#x27;s explicit &#x27;by contrast&#x27; comparison is unhedged.</note><term>STUDY</term><term>simple HDF5-backed class ANNDATA</term></span>
    </spanGrp>
  </standOff>
  <text>
    <body>
        <p><anchor xml:id="a0"/> Abstract</p>
        <p><anchor xml:id="a1"/>Scanpy is a scalable toolkit for analyzing single-cell gene expression data. It includes methods for preprocessing, visualization, clustering, pseudotime and trajectory inference, differential expression testing, and simulation of gene regulatory networks<anchor xml:id="a2"/>. Its Python-based implementation efficiently deals with data sets of more than one million cells ( https://github.com/theislab/Scanpy ). <anchor xml:id="a3"/>Along with Scanpy , we present AnnData , a generic class for handling annotated data matrices<anchor xml:id="a4"/> ( https://github.com/theislab/anndata ).</p>
        <p>Ask a research question</p>
        <p>Get related insights from Springer Nature content.</p>
        <p>How can lineage reconstruction be robustly performed on million-cell data?</p>
        <p>How to scale single-cell analysis tools for large, high-dimensional datasets?</p>
        <p>Or ask your own question</p>
        <p>Similar content being viewed by others</p>
        <p>scAlign: a tool for alignment, integration, and rare cell identification from scRNA-seq data</p>
        <p>Article   Open access   14 August 2019</p>
        <p>SingleScan: a comprehensive resource for single-cell sequencing data processing and mining</p>
        <p>Article   Open access   07 December 2023</p>
        <p>Single-Cell RNA Sequencing Data Analysis</p>
        <p>Chapter</p>
        <p>© 2025</p>
        <p>Explore related subjects</p>
        <p>Discover the latest articles, books and news in related subjects, suggested using machine learning.</p>
        <p>Gene Expression Analysis</p>
        <p>Gene expression profiling</p>
        <p>Genome-wide analysis of gene expression</p>
        <p>Microarray analysis</p>
        <p>Transcriptomics</p>
        <p>High-throughput Cell Screening</p>
        <p>Gene Expression Analysis in Cancer Genomics</p>
        <p>Background</p>
        <p><anchor xml:id="a5"/>Simple integrated analysis work flows for single-cell transcriptomic data [ 1 ] have been enabled by frameworks such as SEURAT [ 2 ], MONOCLE [ 3 ], SCDE/PAGODA [ 4 ], MAST [ 5 ], CELL RANGER [ 6 ], SCATER [ 7 ], and SCRAN [ 8 ]. <anchor xml:id="a6"/>However, these frameworks do not scale to the increasingly available large data sets with up to and more than one million cells. Here, we present a framework that overcomes this limitation and provides similar analysis possibilities.<anchor xml:id="a7"/> Moreover, in contrast to the existing R-based frameworks, SCANPY ’s Python-based implementation is easy to interface with advanced machine-learning packages, such as TENSORFLOW [ 9 ].<anchor xml:id="a8"/></p>
        <p>Results</p>
        <p>SCANPY integrates canonical analysis methods in a scalable way</p>
        <p>SCANPY integrates the analysis possibilities of established R-based frameworks and provides them in a scalable and modular form. Specifically, SCANPY provides preprocessing comparable to SEURAT [ 10 ] and CELL RANGER [ 6 ], visualization through TSNE [ 11 , 12 ], graph-drawing [ 13 – 15 ] and diffusion maps [ 11 , 16 , 17 ], clustering similar to PHENOGRAPH [ 18 – 20 ], identification of marker genes for clusters via differential expression tests and pseudotemporal ordering via diffusion pseudotime [ 21 ], which compares favorably [ 22 ] with MONOCLE 2 [ 22 ], and WISHBONE [ 23 ] (Fig.  1 a).</p>
        <p>Fig. 1 Full size image</p>
        <p>a SCANPY ’s analysis features. We use the example of 68,579 peripheral blood mononuclear cells of [ 6 ]. We regress out confounding variables, normalize, and identify highly variable genes. TSNE and graph-drawing (Fruchterman–Reingold) visualizations show cell-type annotations obtained by comparisons with bulk expression. Cells are clustered using the Louvain algorithm. Ranking differentially expressed genes in clusters identifies the MS4A1 marker gene for B cells in cluster 7, which agrees with the bulk labels. We use pseudotemporal ordering from a root cell in the CD34+ cluster and detect a branching trajectory, visualized with TSNE and diffusion maps. b Speedup over CELL RANGER R kit. We consider representative steps of the analysis [ 6 ]. c Visualizing and clustering 1.3 million cells. The data, brain cells from E18 mice, are publicly available from 10x Genomics. PCA = principal component analysis, DC = diffusion component</p>
        <p>SCANPY is benchmarked in comparisons with established packages</p>
        <p><anchor xml:id="a9"/>In a detailed clustering tutorial of 2700 peripheral blood mononuclear cells (PBMCs), adapted from one of SEURAT ’s tutorials ( http://satijalab.org/seurat/pbmc3k_tutorial.html ) [ 2 ], all steps starting from raw count data to the identification of cell types are carried out, providing speedups between 5 and 90 times in each step ( https://github.com/theislab/scanpy_usage/tree/master/170505_seurat ).<anchor xml:id="a10"/> <anchor xml:id="a11"/>Benchmarking against the more run-time optimized CELL RANGER R kit [ 6 ], we demonstrate a speedup of 5 to 16 times for a data set of 68,579 PBMCs<anchor xml:id="a12"/> (Fig.  1 a,b, https://github.com/theislab/scanpy_usage/tree/master/170503_zheng17 ) [ 6 ]. <anchor xml:id="a13"/>Moreover, we demonstrate the feasibility of analyzing 1.3 million cells without subsampling in a few hours of computing time on eight cores of a small computing server<anchor xml:id="a14"/> (Fig.  1 c, https://github.com/theislab/scanpy_usage/tree/master/170522_visualizing_one_million_cells ). Thus, SCANPY provides tools with speedups that enable an analysis of data sets with more than one million cells and an interactive analysis with run times of the order of seconds for about 100,000 cells.</p>
        <p>In addition to the mentioned standard clustering-based analyses approaches, we demonstrate the reconstruction of branching developmental processes via diffusion pseudotime [ 21 ] as in the original paper ( https://github.com/theislab/scanpy_usage/tree/master/170502_haghverdi16 ), the simulation of single cells using literature-curated gene regulatory networks based on the ideas of [ 24 ] ( https://github.com/theislab/scanpy_usage/tree/master/170430_krumsiek11 ), and the analysis of deep-learning results for single-cell imaging data [ 25 ] ( https://github.com/theislab/scanpy_usage/tree/master/170529_images ).</p>
        <p>SCANPY introduces efficient modular implementation choices</p>
        <p><anchor xml:id="a15"/>With SCANPY , we introduce the class ANNDATA —with a corresponding package ANNDATA —which stores a data matrix with the most general annotations possible: annotations of observations (samples, cells) and variables (features, genes), and unstructured annotations.<anchor xml:id="a16"/> <anchor xml:id="a17"/>As SCANPY is built around that class, it is easy to add new functionality to the toolkit. All statistics and machine-learning tools extract information from a data matrix, which can be added to an ANNDATA object while leaving the structure of ANNDATA unaffected.<anchor xml:id="a18"/> <anchor xml:id="a19"/>ANNDATA is similar to R’s EXPRESSIONSET [ 26 ], but supports sparse data and allows HDF5-based backing of ANNDATA objects on disk, a format independent of platform, framework, and language.<anchor xml:id="a20"/> <anchor xml:id="a21"/>This allows operating on an ANNDATA object without fully loading it into memory—the functionality is offered via ANNDATA ’s backed mode as opposed to its memory mode<anchor xml:id="a22"/>.<anchor xml:id="a23"/> <anchor xml:id="a24"/>To simplify memory-efficient pipelines, SCANPY ’s functions operate in-place by default but allow the optional non-destructive transformation of objects. Pipelines written this way can then also be run in backed mode to exploit online-learning formulations of algorithms. Almost all of SCANPY ’s tools are parallelized<anchor xml:id="a25"/>.</p>
        <p><anchor xml:id="a26"/>SCANPY introduces a class for representing a graph of neighborhood relations among data points. <anchor xml:id="a27"/>The computation of neighborhood relations is much faster than in the popular reference package [ 27 ]. This is achieved by aggregating rows (observations) in a data matrix to submatrices and computing distances for each submatrix using fast parallelized matrix multiplication.<anchor xml:id="a28"/> Moreover, the class provides several functions to compute random-walk-based metrics that are not available in other graph software<anchor xml:id="a29"/> [ 14 , 28 , 29 ]. <anchor xml:id="a30"/>Typically, SCANPY ’s tools reuse a once-computed, single graph representation of data and hence, avoid the use of different, potentially inconsistent, and computationally expensive representations of data.<anchor xml:id="a31"/></p>
        <p>Conclusions</p>
        <p>SCANPY ’s scalability directly addresses the strongly increasing need for aggregating larger and larger data sets [ 30 ] across different experimental setups, for example within challenges such as the Human Cell Atlas [ 31 ]. Moreover, being implemented in a highly modular fashion, SCANPY can be easily developed further and maintained by a community. The transfer of the results obtained with different tools used within the community is simple, as SCANPY ’s data storage formats and objects are language independent and cross-platform. <anchor xml:id="a32"/>SCANPY integrates well into the existing Python ecosystem, in which no comparable toolkit yet exists.<anchor xml:id="a33"/></p>
        <p>During the revision of this article, the loom file format ( https://github.com/linnarsson-lab/loompy ) was proposed for HDF5-based storage of annotated data. Within a joint effort of facilitating data exchange across different labs, ANNDATA now supports importing and exporting to loom ( https://github.com/linnarsson-lab/loompy ). <anchor xml:id="a34"/>In this context, we acknowledge the discussions with S. Linnarson, which motivated us to extend ANNDATA ’s previously static to a dynamic HDF5 backing<anchor xml:id="a35"/>. Just before submission of this manuscript, a C++ library that provides simple interfacing of HDF5-backed matrices in R was made available as a preprint [ 32 ].</p>
        <p>Methods</p>
        <p>SCANPY ’s technological foundations</p>
        <p>SCANPY ’s core relies on NUMPY [ 33 ], SCIPY [ 34 ], MATPLOTLIB [ 35 ], PANDAS [ 36 ], and H5PY [ 37 ]. Parts of the toolkit rely on SCIKIT-LEARN [ 27 ], STATSMODELS [ 38 ], SEABORN [ 39 ], NETWORKX [ 28 ], IGRAPH [ 14 ], the TSNE package of [ 40 ], and the Louvain clustering package of [ 41 ]. The ANNDATA class—available within the package ANNDATA —relies only on NUMPY , SCIPY , PANDAS , and H5PY .</p>
        <p>SCANPY ’s Python-based implementation allows easy interfacing to advanced machine-learning packages such as TENSORFLOW [ 9 ] for deep learning [ 42 ], LIMIX for linear mixed models [ 43 ], and GPY/GPFLOW for Gaussian processes [ 44 , 45 ]. However, we note that the Python ecosystem comes with less possibilities for classical statistical analyses compared to R.</p>
        <p>Comparison with existing Python packages for single-cell analysis</p>
        <p>Aside from the highly popular SCLVM ( https://github.com/PMBio/scLVM ) [ 46 , 47 ], which uses Gaussian process latent variable models for inferring hidden sources of variation, there are, among others, the visualization frameworks FASTPROJECT ( https://github.com/YosefLab/FastProject ) [ 48 ], ACCENSE ( http://www.cellaccense.com/ ) [ 49 ], and SPRING ( https://github.com/AllonKleinLab/SPRING ) [ 15 ]—the latter uses the JavaScript package ( http://d3js.org D3.js for the actual visualization and Python only for preprocessing—the trajectory inference tool SCIMITAR ( https://github.com/dimenwarper/scimitar ), the clustering tool PHENOGRAPH ( https://github.com/jacoblevine/PhenoGraph ) [ 19 ], the single-cell experiment design tool MIMOSCA ( https://github.com/asncd/MIMOSCA )[ 50 ], UMIS ( https://github.com/vals/umis ) for handling raw read data [ 51 ], the tree-inference tool ECLAIR ( https://github.com/GGiecold/ECLAIR ) [ 52 ], and the framework FLOTILLA ( https://github.com/yeolab/flotilla ), which comes with modules for simple visualization, simple clustering, and differential expression testing. <anchor xml:id="a36"/>Hence, only the latter provides a data analysis framework that solves more than one specific task. In contrast to SCANPY , however, FLOTILLA is neither targeted at single-cell nor at large-scale data and does not provide any graph-based methods, which are the core of SCANPY . Also, FLOTILLA is built around a complicated class STUDY , which contains data, tools, and plotting functions. SCANPY , by contrast, is built around a simple HDF5-backed class ANNDATA , which makes SCANPY both scalable and extendable (law of Demeter)<anchor xml:id="a37"/>.</p>
        <p>Availability and requirements</p>
        <p>SCANPY ’s and ANNDATA ’s open-source code are maintained on GITHUB ( https://github.com/theislab/scanpy , https://github.com/theislab/anndata ) and published under the BSD3 license.</p>
        <p>SCANPY and ANNDATA are released via the Python packaging index: https://pypi.python.org/pypi/scanpy and https://pypi.python.org/pypi/anndata .</p>
        <p>Demonstrations and benchmarks discussed in the main text are all stored at https://github.com/theislab/scanpy_usage and summarized here:</p>
        <p>Analyzing 68,579 PBMCs (Fig.  1 ) in a comparison with the Cell Ranger R kit [ 6 ]: https://github.com/theislab/scanpy_usage/tree/master/170503_zheng17 .</p>
        <p>Clustering and identifying cell types, adapted from and benchmarked with http://satijalab.org/seurat/pbmc3k_tutorial.html and one of Seurat ’s tutorials [ 2 ]: https://github.com/theislab/scanpy_usage/tree/master/170505_seurat .</p>
        <p>Visualizing and clustering 1.3 million cells (Fig.  1 c): https://github.com/theislab/scanpy_usage/tree/master/170522_visualizing_one_million_cells .</p>
        <p>Reconstructing branching processes via diffusion pseudotime [ 21 ]: https://github.com/theislab/scanpy_usage/tree/master/170502_haghverdi16 .</p>
        <p>Simulating single cells using gene regulatory networks [ 24 ]: https://github.com/theislab/scanpy_usage/tree/master/170430_krumsiek11 .</p>
        <p>Analyzing deep-learning results for single-cell images [ 25 ]: https://github.com/theislab/scanpy_usage/tree/master/170529_images .</p>
        <p>The data sets used in demonstrations and benchmarks are three data sets from 10x Genomics.</p>
        <p>Programming language: Python</p>
        <p>Operating system: Linux, Mac OS and Windows<anchor xml:id="a38"/></p>
    </body>
  </text>
</TEI>
