From 60e377e397b64d1fd51d0662dbaa0d7976af045a Mon Sep 17 00:00:00 2001 From: Jayaram Kancherla Date: Tue, 16 Jul 2024 16:14:21 -0700 Subject: [PATCH] final changes --- .gitignore | 2 +- assets/single-cell-space.jpg | Bin 0 -> 57426 bytes index.qmd | 4 +- requirements.txt | 1 - tutorials/annotate_cell_types.qmd | 183 +++++++++++++++--------------- tutorials/genomic_ranges.qmd | 47 ++++---- tutorials/sessioninfo.qmd | 2 +- 7 files changed, 119 insertions(+), 120 deletions(-) create mode 100644 assets/single-cell-space.jpg diff --git a/.gitignore b/.gitignore index 15403fd..324eab1 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,4 @@ chapters/zilinois_lung_with_celltypist/ *.tiledb *_cache *_files -tutorials/cache/* \ No newline at end of file +tutorials/cache/*`` \ No newline at end of file diff --git a/assets/single-cell-space.jpg b/assets/single-cell-space.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3a0e3a5c46c3778013351a7b3dd96987b5d1b1da GIT binary patch literal 57426 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]dhHy$eiFPVh{Iga&DtN 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 literal 0 HcmV?d00001 diff --git a/index.qmd b/index.qmd index 616537f..2f978db 100644 --- a/index.qmd +++ b/index.qmd @@ -20,6 +20,8 @@ on [GitHub](https://github.com/BiocPy). - [Jayaram Kancherla](https://github.com/jkanche) - [Aaron Lun](https://github.com/LTLA) +Always looking for more contributions from the community to improve our packages! Checkout the issues or discussion in our GitHub organization. + ---- ## Other resources @@ -29,4 +31,4 @@ on [GitHub](https://github.com/BiocPy). ## Developer notes -This is a reproducible Quarto book with reusable snippets. To learn more about Quarto books visit . Check out [Reproduce me](./chapters/sessioninfo.qmd) for more information. \ No newline at end of file +This is a reproducible Quarto book with reusable snippets. To learn more about Quarto books visit . Check out [Session Info](./chapters/sessioninfo.qmd) for more information. \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 904faf6..f248bea 100644 --- a/requirements.txt +++ b/requirements.txt @@ -20,5 +20,4 @@ celldex scrnaseq anndata matplotlib -scanpy geniml diff --git a/tutorials/annotate_cell_types.qmd b/tutorials/annotate_cell_types.qmd index f3b7289..7e1a822 100644 --- a/tutorials/annotate_cell_types.qmd +++ b/tutorials/annotate_cell_types.qmd @@ -1,24 +1,22 @@ # Tutorial 2: Access single-cell datasets from `scRNAseq` collection and annotate cell types -Welcome to this tutorial on annotating single-cell datasets with reference collections. The **scRNAseq** ([R/Bioc](https://bioconductor.org/packages/devel/data/experiment/html/scRNAseq.html), [Python](https://github.com/BiocPy/scrnaseq)) package provides access to public single-cell RNA-seq datasets for use by other Bioconductor/BiocPy packages and workflows. These datasets are stored in language-agnostic representations described in [ArtifactDB](https://github.com/artifactdb), enabling easy access to datasets and analysis results across multiple programming languages such as R and Python. We will showcase how to integrate and process single-cell datasets across languages, such as R and Python, and how to annotate cell types using reference datasets. +Welcome to this tutorial on annotating single-cell datasets with reference collections. The **scRNAseq** ([R/Bioc](https://bioconductor.org/packages/devel/data/experiment/html/scRNAseq.html), [Python](https://github.com/BiocPy/scrnaseq)) package provides access to public single-cell RNA-seq datasets for use by other Bioconductor/BiocPy packages and workflows. These datasets are stored in language-agnostic representations described in [ArtifactDB](https://github.com/artifactdb), enabling easy access to datasets and analysis results across multiple programming languages such as R and Python. We will showcase how to integrate and process single-cell datasets across languages, such as R and Python, and how to annotate cell types using reference datasets. ## Outline In this tutorial, you will learn how to: -- Install and set up BiocPy packages in your Python environment. -- Explore the `scrnaseq` package and access public single-cell RNA-seq datasets. -- Perform basic operations on `SingleCellExperiment` objects, the core data structure for single-cell data. -- Annotate cell types using reference datasets from the `celldex` package. - -Let's dive into the process! +1. Install and set up BiocPy packages in your Python environment. +2. Explore the `scrnaseq` package and access public single-cell RNA-seq datasets. +3. Perform basic operations on `SingleCellExperiment` objects, the core data structure for single-cell data. +4. Annotate cell types using reference datasets from the `celldex` package. ## Prerequisites Before we begin, please ensure that you have the following prerequisites installed: -- Python 3.8 or later with dependencies listed [here]([../requirements.txt](https://github.com/BiocPy/BiocWorkshop2024/blob/master/requirements.txt)). -- R 4.4.0 and Bioconductor packages listed [here]([../rpackages.R](https://github.com/BiocPy/BiocWorkshop2024/blob/master/rpackages.R)). +- Python 3.8 or later with dependencies listed [here](https://github.com/BiocPy/BiocWorkshop2024/blob/master/requirements.txt). +- R 4.4.0 and Bioconductor packages listed [here](https://github.com/BiocPy/BiocWorkshop2024/blob/master/rpackages.R). ## Installation @@ -42,7 +40,6 @@ BiocManager::install(c("scRNAseq", "celldex", "SingleR"), This will install the `scRNAseq`, `celldex`, `SingleR`, packages from Bioconductor. - ::: ## Accessing and Exploring Single-Cell Datasets @@ -99,7 +96,7 @@ This R|Python code searches for datasets containing the term "pancreas" and disp #### Advanced Searches -For more complex searches involving boolean operations, use `define_text_query()` in Python or `defineTextQuery()` in R. Here’s an example to find datasets using the mouse reference genome (`GRCm38`) and containing the words `neuro` or `pancrea`. +For more complex searches involving boolean operations, use `define_text_query()` in Python or `defineTextQuery()` in R. Here's an example to find datasets using the mouse reference genome (`GRCm38`) and containing the words `neuro` or `pancrea`. ::: {.callout-tip} Check out the reference manual for more details and usage of these functions. @@ -155,14 +152,14 @@ For this tutorial, let's download the `zeisel-brain` dataset: ## Python ```{python} import scrnaseq -sce = scrnaseq.fetch_dataset("zeisel-brain-2015", "2023-12-14", realize_assays=True) +sce = scrnaseq.fetch_dataset("zeisel-brain-2015", "2023-12-14") print(sce) ``` ## R ```r -sce <- fetchDataset("zeisel-brain-2015", "2023-12-14", realize.assays=TRUE) +sce <- fetchDataset("zeisel-brain-2015", "2023-12-14") sce ``` @@ -178,23 +175,46 @@ For more details on the design, refer to the [BiocPy developer guide](https://gi This Python code demonstrates basic operations on a `SingleCellExperiment` object, including retrieving assay names, column names, column metadata, accessing counts, and coercing to an `AnnData` object for interoperability with existing analysis ready eco-systems in Python. -```{python} -## repeated because quarto's build does not keep state of python snippets across the notebook. -import scrnaseq -sce = scrnaseq.fetch_dataset("zeisel-brain-2015", "2023-12-14") +::: {.panel-tabset} +## Python + +```{python} print("assays: ", sce.get_assay_names()) # or sce.assay_names print("column names: ", sce.get_column_names()) # or sce.column_names -print("column metadata:", sce.get_column_data()) # or sce.column_data +print("column metadata: ", sce.get_column_data()) # or sce.column_data -print("access counts ", sce.assays["counts"]) # or # sce.assay("counts") +print("access counts: ", sce.assays["counts"]) # or # sce.assay("counts") +``` -print("coerce to AnnData", sce.to_anndata()) +:::{.callout-note} +The package uses [delayed arrays](https://github.com/biocpy/delayedarray), to load file-backed arrays and matrices. This reduces memory usage when loading large datasets. This package provides similar functionality to the R/Bioconductor's [DelayedArray](https://www.bioconductor.org/packages/release/bioc/html/DelayedArray.html) eco-system. +::: + +```{python} +from delayedarray import to_scipy_sparse_matrix +print("counts as csr: ") +print(repr(to_scipy_sparse_matrix(sce.assays["counts"], "csc"))) ``` -TODO: convert matrix to scipy sparse +or realize the entire matrix when loaded from disk, + +```{python} +sce = scrnaseq.fetch_dataset( + "zeisel-brain-2015", "2023-12-14", + realize_assays=True) +print(sce) +``` + +We also provide coercions to various package to take advantage of methods in the Python ecosystem, e.g. scverse and AnnData + +```{python} +print("coerce to AnnData: ", sce.to_anndata()) +``` + +::: ## Annotate Cell Types @@ -210,7 +230,7 @@ Similar to the `scRNAseq` package, the `celldex` package provides access to the The `celldex` package is available on [R/Bioconductor](https://bioconductor.org/packages/devel/data/experiment/html/celldex.html) and [PyPI](https://github.com/BiocPy/celldex). ::: -For this tutorial, let's download the [Immunological Genome Project (immgen)](https://www.immgen.org/) reference from `celldex` using `fetch_reference()` in Python or `fetchReference()` in R. +For this tutorial, let's download the [Mouse RNA-seq](https://www.immgen.org/) reference from `celldex` using `fetch_reference()` in Python or `fetchReference()` in R. This reference consists of a collection of mouse bulk RNA-seq data sets downloaded from the gene expression omnibus ([Benayoun et al. 2019](https://doi.org/10.1101/gr.240093.118)). A variety of cell types are available, again mostly from blood but also covering several other tissues. ::: {.panel-tabset} @@ -218,19 +238,21 @@ For this tutorial, let's download the [Immunological Genome Project (immgen)](ht ```{python} import celldex -immgen_ref = celldex.fetch_reference("immgen", "2024-02-26", realize_assays=True) -print(immgen_ref) +mouse_rnaseq_ref = celldex.fetch_reference( + "mouse_rnaseq", "2024-02-26", + realize_assays=True) +print(mouse_rnaseq_ref) ``` ## R ```r suppressWarnings(library(celldex)) -immgen_ref <- fetchReference("immgen", "2024-02-26", realize.assays=TRUE) -immgen_ref +mouse_rnaseq_ref <- fetchReference("mouse_rnaseq", "2024-02-26", realize.assays=TRUE) +mouse_rnaseq_ref ``` ::: -Now, let's identify cells from the `zeisel-brain` dataset using the `immgen` reference dataset. +Now, let's identify cells from the `zeisel-brain` dataset using the `mouse_rnaseq` reference dataset. ::: {.panel-tabset} @@ -238,15 +260,9 @@ Now, let's identify cells from the `zeisel-brain` dataset using the `immgen` ref ```{python} import singler -import scrnaseq -sce = scrnaseq.fetch_dataset("zeisel-brain-2015", "2023-12-14", realize_assays=True) - -import celldex -immgen_ref = celldex.fetch_reference("immgen", "2024-02-26", realize_assays=True) - matches = singler.annotate_single( test_data=sce, - ref_data = immgen_ref, + ref_data = mouse_rnaseq_ref, ref_labels = "label.main" ) @@ -255,98 +271,81 @@ import pandas as pd pd.Series(matches["best"]).value_counts() ``` -Note: Since the python snippets use reticulate when built through Quarto, it does not keep the objects from prior code-blocks. Hence the code chunk is longer. - ## R ```r suppressWarnings(library(SingleR)) -cell_labels <- SingleR(test = assay(sce, "counts"), ref = immgen_ref, labels = immgen_ref$label.main) +cell_labels <- SingleR(test = assay(sce, "counts"), ref = mouse_rnaseq_ref, labels = mouse_rnaseq_ref$label.main) table(cell_labels$labels) ``` ::: -## Visualizing Single-Cell Data +## Analyze Single-cell RNA-seq datasets -I can't have a tutorial without a section on visualization or figures. - -TODO: generate embeddings and then visualize clusters +![single-cell-methods](../assets/single-cell-space.jpg) +Aaron has implemented the single-cell methods from scran in C++. This allows us to reuse the same implementation in JS and develop applications for analyzing single-cell data ([Kana](https://github.com/kanaverse/kana)), or in Python through the [scranpy](https://github.com/BiocPy/scranpy) package. This avoids different interpretations of the analysis results by switching programming languages (Pachter et al, [The impact of package selection and versioning on single-cell RNA-seq analysis | bioRxiv](https://www.biorxiv.org/content/10.1101/2024.04.04.588111v1) ) -::: {.panel-tabset} - -## Python -We will use the seaborn and matplotlib packages in Python to create visualizations. First, let's visualize the cell type annotations. +To analyze the dataset, ```{python} -import seaborn as sns -import matplotlib.pyplot as plt -import pandas as pd +import scranpy -cell_labels = pd.Series(matches["best"]).value_counts() +results = scranpy.analyze_sce(sce) -sns.barplot(x=cell_labels.index, y=cell_labels.values) -plt.xticks(rotation=45, ha='right') -plt.title("Cell Type Annotations") -plt.xlabel("Cell Type") -plt.ylabel("Count") -plt.show() +# results is a complex object, lets explore the umap and tsne dimensions +print(results.tsne) ``` -## R +### Seems like magic? -We will use the ggplot2 package in R to create visualizations. First, let's visualize the cell type annotations. +Running the `analyze_sce()` function uses the default parameters to run the single-cell workflow. If you want to customize or want to have fine-grained control on the analysis steps, set the parameter `dry_run=True`. -```r -suppressWarnings(library(SingleR)) -suppressWarnings(library(ggplot2)) -cell_labels <- SingleR(test = assay(sce, "counts"), ref = immgen_ref, labels = immgen_ref$label.main) -sce$labels <- cell_labels$labels - -ggplot(as.data.frame(colData(sce)), aes(x = labels)) + - geom_bar() + - theme(axis.text.x = element_text(angle = 45, hjust = 1)) + - labs(title = "Cell Type Annotations", x = "Cell Type", y = "Count") +:::{.callout-note} +This prints out the exact series of steps the function does under the hood to perform the analysis. You can then use this to customize the analysis to your specific dataset or use case. +::: + +```{python} +print(scranpy.analyze_sce(sce, dry_run=True)) ``` +:::{.callout-tip} +Users can also run individual steps from the analysis without having to perform the full analysis, e.g. compute log normalized counts or find markers, etc. ::: -## Homework: Performing Differential Expression Analysis - -Differential expression analysis helps identify genes that are differentially expressed between different cell types or conditions. Let's explore how to identify markers for various cell types. +## Visualize Results -### Differential Expression Analysis in Python +I can't have a tutorial without a section on visualization or figures. -We will use the scanpy package in Python to perform differential expression analysis. +We will use the seaborn and matplotlib packages in Python to create visualizations. We'll plot the t-SNE embedding and color the cells by their cluster assignments. -```python -import scanpy as sc +```{python} +import seaborn as sns +sns.scatterplot( + x=results.tsne.x, y=results.tsne.y, + hue=results.clusters, palette="deep" +) +``` -import scrnaseq -sce = scrnaseq.fetch_dataset("zeisel-brain-2015", "2023-12-14", realize_assays=True) +or the UMAP embedding with the cell types we identified from `celldex` -import celldex -immgen_ref = celldex.fetch_reference("immgen", "2024-02-26", realize_assays=True) -import singler -matches = singler.annotate_single( - test_data=sce, - ref_data=immgen_ref, - ref_labels="label.main" +```{python} +import seaborn as sns +sns.scatterplot( + x=results.umap.x, y=results.umap.y, + hue=matches["best"][:3002], palette="deep" ) +``` -# Prepare the data -adata, _ = sce.to_anndata() -adata.obs['labels'] = matches["best"] -adata.X = sc.pp.normalize_total(adata, target_sum=1e4, inplace=False)['X'] +:::{.callout-caution} +During the QC step, some cells were filtered, hence we filter the matches and this is incorrect (since we don't know which cells were filtered). -# Perform differential expression analysis -sc.tl.rank_genes_groups(adata, groupby='labels') -sc.pl.rank_genes_groups(adata, n_genes=20, sharey=False) -``` +We'll leave this as an exercise for the reader to change the order of steps: 1) run the dataset through the QC step 2) filter cells, and then 3) annotate using singleR. +::: Congratulations! You have now completed the tutorial on accessing single-cell datasets using `scRNAseq` and `ArtifactDB`, and annotating cell types using reference datasets from `celldex`. For more detailed usage and advanced analyses, refer to the respective documentation of these packages. -By integrating R and Python workflows, you can leverage the strengths of both languages and perform comprehensive single-cell analysis. Keep exploring and happy analyzing! +By integrating R and Python workflows, you can leverage the strengths of both languages and perform comprehensive single-cell analysis. Keep exploring and happy analyzing! \ No newline at end of file diff --git a/tutorials/genomic_ranges.qmd b/tutorials/genomic_ranges.qmd index 648119e..27975ee 100644 --- a/tutorials/genomic_ranges.qmd +++ b/tutorials/genomic_ranges.qmd @@ -1,20 +1,19 @@ # Tutorial 1: `GenomicRanges` and range-based analyses -Genomic range operations are fundamental to many bioinformatics analyses. They allow us to work with intervals of genomic coordinates, which is crucial for understanding the relationships between different genomic features such as genes, regulatory elements, and experimental data like ChIP-seq peaks. In this session, we'll explore how to work with genomic interval data using BiocPy's [GenomicRanges](https://github.com/BiocPy/GenomicRanges/) packages, which provide Python implementations to the R/Bioconductor [GenomicRanges package](https://github.com/Bioconductor/GenomicRanges). +Genomic range operations are fundamental to many bioinformatics analyses. They allow us to work with intervals of genomic coordinates, which is crucial for understanding the relationships between different genomic features such as genes, regulatory elements, and experimental data like ChIP-seq peaks. In this tutorial, we'll explore how to work with genomic interval data using BiocPy's [GenomicRanges](https://github.com/BiocPy/GenomicRanges/) package, which provides Python implementations similar to the R/Bioconductor [GenomicRanges package](https://github.com/Bioconductor/GenomicRanges). ## Outline In this workshop, we'll walk through several key aspects of working with genomic ranges in Python: -1. Reading Genomic Data: We'll start by reading in genomic data from RDS files, including CpG islands and gene annotations. +1. Reading Genomic Data: We'll start by reading in genomic data from RDS files, including exon positions grouped by transcripts. 2. Basic Genomic Operations: We'll cover fundamental operations like finding transcription start sites (TSS) and promoter regions. 3. Overlap Analysis: We'll learn how to find overlaps between different genomic features, a common task in many analyses. 4. Advanced Operations: We'll explore more complex operations like finding peaks within specific regions and resizing genomic intervals. ## Prerequisites -Before we begin, please ensure that you have the following installed: - +Before we begin, please ensure that you have the following packages installed: ### Installation @@ -27,7 +26,7 @@ Let's start by installing the required packages for R and Python. You can install the Python packages using pip: ```bash -pip install -U biocutils genomicranges rds2py numpy pandas +pip install -U biocutils genomicranges rds2py numpy pandas geniml ``` ## R @@ -41,8 +40,8 @@ BiocManager::install(c("AnnotationHub"), ## 1. Save Annotations as RDS -Let's download the human reference genome and save the exon positions group by transcripts. -We need do a bit of pre-processing to get this information. +Let's download the human reference genome and save the exon positions grouped by transcripts. +We need to do a bit of pre-processing to get this information. For the purpose of the tutorial, we'll limit the exons to chromosome 22. @@ -72,8 +71,8 @@ The [rds2py](https://github.com/biocpy/rds2py) Python package allows us to read Reading an RDS file with rds2py involves two steps: -- Parse the RDS file into a Python dictionary containing data, its attributes and associated metadata. -- Convert this dictionary into a suitable Python object using specific parser functions. +1. Parse the RDS file into a Python dictionary containing data, its attributes, and associated metadata. +2. Convert this dictionary into a suitable Python object using specific parser functions. This process allows a seamless transition between R and Python for bioinformatics analyses. @@ -99,7 +98,7 @@ Now, let's perform some basic operations like finding Transcription Start Sites ### 2.1 Create a `GenomicRangesList` by gene -To identify TSS or define promoter regions, Let's first reprocess the input to create a `GenomicRangesList` by gene symbols. +To identify TSS or define promoter regions, let's first reprocess the input to create a `GenomicRangesList` by gene symbols. ::: {.panel-tabset} @@ -114,13 +113,13 @@ all_ranges = by_tx.as_genomic_ranges() Then we split the object using the `gene_name` metadata column in `mcols()`. :::{.callout-important} -We provide accessors to get or set attributes of the class. Most folks in Python may be familar with direct access to class members (via properties or @property) should generally be avoided, as it is too easy to perform modifications via one liners with the class.property on the left-hand-side of an assignment. +We provide accessors to get or set attributes of the class. Most folks in Python may be familiar with direct access to class members (via properties or @property), but this should generally be avoided, as it is too easy to perform modifications via one-liners with the class.property on the left-hand side of an assignment. For more information, please refer to our [developer guide](https://github.com/BiocPy/developer_guide). ::: :::{.callout-note} -While gene id's are unique, gene symbols are not. In addition, this list has genes with no symbols. +While gene IDs are unique, gene symbols are not. In addition, this list has genes with no symbols. ::: ```{python} @@ -139,7 +138,7 @@ Transcription Start Sites (TSS) are the locations where transcription of a gene ::: {.panel-tabset} -Let's use the `range()` method to the get the full extent of each gene. +Let's use the `range()` method to get the full extent of each gene. ## Python @@ -159,7 +158,7 @@ print("as GenomicRanges:") print(gr_by_gene) ``` -Then resizing to a width of 1 base pair at the start of each range to pinpoint the TSS. +Then we resize to a width of 1 base pair at the start of each range to pinpoint the TSS. ```{python} tss = gr_by_gene.resize(width=1, fix="start") @@ -184,7 +183,7 @@ print(promoters) ``` :::{.callout-note} -Please be aware that because gene symbols may not be unique, this GenomicRanges object might contain duplicates. One might want to resolve duplicate symbols by making the symbols unique. We will leave this as an exercise to the reader. +Please be aware that because gene symbols may not be unique, this GenomicRanges object might contain duplicates. You might want to resolve duplicate symbols by making the symbols unique. We will leave this as an exercise for the reader. ::: ::: @@ -197,7 +196,7 @@ A common task in genomic analysis is finding overlaps between different genomic ChIP-seq (Chromatin Immunoprecipitation followed by sequencing) is a method used to identify binding sites of DNA-associated proteins. The peaks represent regions where a protein of interest is likely bound to the DNA. We're focusing on chromosome 22 for this example to keep the dataset manageable. -For the purpose of this tutorial, lets download a bed file containing peaks from a ChIP-seq experiments on "Human B cells" to identify "EZH2" binding sites (from ENCODE) and cataloged in [bedbase.org](https://bedbase.org/bed/be4054acf6e3feeb4dc490e6430e358e). +For the purpose of this tutorial, let's download a bed file containing peaks from a ChIP-seq experiment on "Human B cells" to identify "EZH2" binding sites (from ENCODE) and cataloged in [bedbase.org](https://bedbase.org/bed/be4054acf6e3feeb4dc490e6430e358e). ::: {.panel-tabset} @@ -234,7 +233,7 @@ print(overlaps[:10]) ``` :::{.callout-note} -Find overlaps returns a `list` with the same length as TSS, indicating which indices from peaks overlap with each of the TSS. Ideally, we would want to return a `Hits` object similar to Bioconductor implementation. +`find_overlaps` returns a `list` with the same length as TSS, indicating which indices from peaks overlap with each of the TSS. Ideally, we would want to return a `Hits` object similar to the Bioconductor implementation. **TODO: Future plans to convert this into a `Hits` object.** ::: @@ -264,7 +263,7 @@ print(peaks_by_tss_ignoring_strand) ``` :::{.callout-note} -This yields same results for this particular scenario, but may not if the 'peaks' contain stand information. +This yields the same results for this particular scenario, but may not if the 'peaks' contain strand information. ::: ::: @@ -320,7 +319,7 @@ Let's explore some more complex operations that are often used in genomic analys ### 4.1 Comparing Exonic vs. Intronic Binding -Let's first identify intro regions. We will use the `by_gene` object we created that contains a `GenomicRangesList` split by gene. +Let's first identify intron regions. We will use the `by_gene` object we created that contains a `GenomicRangesList` split by gene. ::: {.panel-tabset} @@ -355,7 +354,7 @@ print(f"Percentage of peaks overlapping with introns: {percent_intronic:.2f}%") ::: :::{.callout-note} -These add up to over 100%, because some peaks overlap both introns and exons depending on how wide the peaks are. Ideally you may want to filter the peaks based on preference as you annotate them with TSS, promoters etc. +These percentages add up to over 100% because some peaks overlap both introns and exons, depending on how wide the peaks are. Ideally, you may want to filter the peaks based on preference as you annotate them with TSS, promoters, etc. ::: This comparison can help determine if the protein of interest shows a preference for binding in exonic or intronic regions, which could suggest different functional roles (e.g., splicing regulation for exonic binding vs. potential enhancer activity for intronic binding). @@ -363,8 +362,8 @@ This comparison can help determine if the protein of interest shows a preference ### 4.2 Finding Overlaps with the first exon :::{.callout-note} -- This is by transcript. -- Not really sure what the rationale would be, but we are mostly showcasing complex genomic operations that are possible with the package. +- This analysis is performed by transcript. +- The rationale for this analysis may vary, but we are mostly showcasing complex genomic operations that are possible with the package. ::: Let's first put together a `GenomicRanges` object containing the first exon for each transcript. @@ -379,7 +378,7 @@ for txid, grl in by_tx: all_first.append(grl.sort()[0]) ``` -Then we combine all the individual genomic elements. The [biocutils](https://github.com/BiocPy/BiocUtils) package provides utilities mostly convenient aspects of R that aren't provided by base Python and generics. One of these generics is the `'combine'` operation that to merge or concatenate various Bioconductor classes. +Then we combine all the individual genomic elements. The [biocutils](https://github.com/BiocPy/BiocUtils) package provides utilities for convenient aspects of R that aren't provided by base Python and generics. One of these generics is the `'combine'` operation that merges or concatenates various Bioconductor classes. ```{python} from biocutils import combine_sequences @@ -406,7 +405,7 @@ print(shifted_peaks) Resizing and shifting genomic ranges can be useful in various contexts. For example: - Narrowing peaks might help focus on the center of ChIP-seq binding sites. -- Shifting ranges can be used to look at regions adjacent to your features of interest. e.g. defining a crips cleavage site from the guide binding site. +- Shifting ranges can be used to look at regions adjacent to your features of interest. e.g. defining the predicted CRISPR cleavage site based on the position of the CRISPR gRNA sequence. These operations demonstrate the flexibility of genomic range manipulations, which can be useful for fine-tuning analyses or testing hypotheses about the spatial relationships between genomic features. diff --git a/tutorials/sessioninfo.qmd b/tutorials/sessioninfo.qmd index 6da378e..18d6e2c 100644 --- a/tutorials/sessioninfo.qmd +++ b/tutorials/sessioninfo.qmd @@ -1,4 +1,4 @@ -# Reproduce me! {.unnumbered} +# Session Info! {.unnumbered} The code base for this repository is available at [https://github.com/BiocPy/tutorial](https://github.com/BiocPy/tutorial).