Protein2Tissue is a Bioconductor package for tissue
enrichment analysis of protein and gene lists. Given a set of proteins
or genes of interest and a background set, the package identifies which
tissues are significantly over-represented using statistical tests.
Results can be explored through a suite of visualisation functions
including heatmaps, bar charts, network plots, and GO enrichment
analysis.
Gene expression reference data are derived from the Human Protein Atlas (HPA), which classifies genes into three tissue-specific expression categories:
The package ships with ee_tb, an example gene/protein
tissue expression data frame derived from the Human Protein Atlas. It
contains tissue-specific expression classifications for human genes. It
can be inspected directly:
data("ee_tb", package = "Protein2Tissue")
head(ee_tb)
#> Gene Ensembl EntrezID Uniprot Is_secreted Tissue.specificity
#> 1 TSPAN6 ENSG00000000003 7105 O43657 FALSE Low tissue specificity
#> 2 TNMD ENSG00000000005 64102 Q9H2S6 FALSE Tissue enhanced
#> 3 DPM1 ENSG00000000419 8813 O60762 FALSE Low tissue specificity
#> 4 SCYL3 ENSG00000000457 57147 Q8IZE3 FALSE Low tissue specificity
#> 5 C1orf112 ENSG00000000460 55732 Q9NSG2 FALSE Tissue enhanced
#> 6 FGR ENSG00000000938 2268 P09769 FALSE Group enriched
#> Adipose tissue Breast Seminal vesicle Parathyroid gland
#> 1 <NA> <NA> <NA> <NA>
#> 2 Tissue enhanced Tissue enhanced Tissue enhanced <NA>
#> 3 <NA> <NA> <NA> <NA>
#> 4 <NA> <NA> <NA> <NA>
#> 5 <NA> <NA> <NA> Tissue enhanced
#> 6 <NA> <NA> <NA> <NA>
#> Bone marrow Lung Lymphoid tissue Liver Testis Brain Esophagus
#> 1 <NA> <NA> <NA> <NA> <NA> <NA> <NA>
#> 2 <NA> <NA> <NA> <NA> <NA> <NA> <NA>
#> 3 <NA> <NA> <NA> <NA> <NA> <NA> <NA>
#> 4 <NA> <NA> <NA> <NA> <NA> <NA> <NA>
#> 5 <NA> <NA> <NA> <NA> <NA> <NA> <NA>
#> 6 Group enriched Group enriched Group enriched <NA> <NA> <NA> <NA>
#> Gallbladder Intestine Pancreas Ovary Kidney Placenta Cervix Skin Endometrium
#> 1 <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>
#> 2 <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>
#> 3 <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>
#> 4 <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>
#> 5 <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>
#> 6 <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>
#> Skeletal muscle Retina Tongue Heart muscle Choroid plexus Fallopian tube
#> 1 <NA> <NA> <NA> <NA> <NA> <NA>
#> 2 <NA> <NA> <NA> <NA> <NA> <NA>
#> 3 <NA> <NA> <NA> <NA> <NA> <NA>
#> 4 <NA> <NA> <NA> <NA> <NA> <NA>
#> 5 <NA> <NA> <NA> <NA> <NA> <NA>
#> 6 <NA> <NA> <NA> <NA> <NA> <NA>
#> Epididymis Salivary gland Vagina Smooth muscle Adrenal gland Blood vessel
#> 1 <NA> <NA> <NA> <NA> <NA> <NA>
#> 2 <NA> <NA> <NA> <NA> <NA> <NA>
#> 3 <NA> <NA> <NA> <NA> <NA> <NA>
#> 4 <NA> <NA> <NA> <NA> <NA> <NA>
#> 5 <NA> <NA> <NA> <NA> <NA> <NA>
#> 6 <NA> <NA> <NA> <NA> <NA> <NA>
#> Pituitary gland Stomach Urinary bladder Thyroid gland Prostate
#> 1 <NA> <NA> <NA> <NA> <NA>
#> 2 <NA> <NA> <NA> <NA> <NA>
#> 3 <NA> <NA> <NA> <NA> <NA>
#> 4 <NA> <NA> <NA> <NA> <NA>
#> 5 <NA> <NA> <NA> <NA> <NA>
#> 6 <NA> <NA> <NA> <NA> <NA>Key columns in ee_tb:
| Column | Description |
|---|---|
Gene |
HGNC gene symbol |
Ensembl |
Ensembl gene identifier |
tissue |
tissue name |
signal |
expression category |
Tissue.specificity |
RNA specificity class |
Is_secreted |
whether the protein is secreted |
We are going to demonstrate how to test tissue enrichment of proteins
using the example dataset within the Protein2Tissue
package.
Protein2Tissue requires two inputs:
# example input: gene symbols
data("plasma_data", package = "Protein2Tissue")
myList <- plasma_data %>%
filter(Coefficient.Age > 0 & q.Age < 0.05) %>%
pull(UniqueSymbol) %>%
toupper()
# example background: Gene symbols of all detected proteins
myBackground <- toupper(plasma_data$UniqueSymbol)
The identifier types used for the input and background do not have to
match. Use typeKey and typeKeyBg to specify
how each list should be matched to the tissue expression database.
tissueAnalysis() maps your input and background lists
against the reference database (here we are using the shipped dataset in
the package derived from the Human Protein Atlas database) and returns
an Enrichment S4 object:
result <- tissueAnalysis(
input = myList,
background = myBackground,
typeKey = "Gene", # identifier type for input
typeKeyBg = "Gene" # identifier type for background
)
#> Warning: 143 protein(s) in the background list not found in the database and
#> have been removed.
#> Warning: 38 protein(s) in the input list not found in the database and have
#> been removed.The Enrichment object has two slots:
# matched input proteins with HPA annotations
getInput(result)[1:6,1:6]
#> Gene Ensembl EntrezID Uniprot Is_secreted Tissue.specificity
#> 1 CGA ENSG00000135346 1081 P01215 TRUE Tissue enriched
#> 2 SOST ENSG00000167941 50964 Q9BQB4 TRUE Tissue enriched
#> 3 ARFIP2 ENSG00000132254 23647 P53365 FALSE Low tissue specificity
#> 4 GDF15 ENSG00000130513 9518 Q99988 TRUE Tissue enhanced
#> 5 MLN ENSG00000096395 4295 P12872 TRUE Tissue enriched
#> 6 PTN ENSG00000105894 5764 P21246 TRUE Tissue enhanced
# matched background proteins with HPA annotations
getBackground(result)[1:6,1:6]
#> Gene Ensembl EntrezID Uniprot Is_secreted Tissue.specificity
#> 1 CGA ENSG00000135346 1081 P01215 TRUE Tissue enriched
#> 2 SOST ENSG00000167941 50964 Q9BQB4 TRUE Tissue enriched
#> 3 ARFIP2 ENSG00000132254 23647 P53365 FALSE Low tissue specificity
#> 4 GDF15 ENSG00000130513 9518 Q99988 TRUE Tissue enhanced
#> 5 MLN ENSG00000096395 4295 P12872 TRUE Tissue enriched
#> 6 IGDCC4 ENSG00000103742 57722 Q8TDY8 FALSE Tissue enhancedA custom database can be substituted if needed:
Enrichment results can be saved to disk as CSV or TSV files:
Before running statistical tests, it is useful to inspect how your input genes are distributed across tissue specificity classes:
This bar chart shows how many of your input genes fall into each specificity class (tissue enriched, group enriched, tissue enhanced, low specificity, etc.), giving a quick overview of the tissue-specific character of your gene list.
heatmapEnrich() shows the tissue expression signal for
each gene in your input as a heatmap:
# restrict to strongly tissue-specific signals only
heatmapEnrich(
result,
inclusion = c("Tissue enriched", "Tissue enhanced")
)Rows are genes and columns are tissues. Colour indicates the signal category — orange cells indicate no tissue-specific signal for that gene-tissue combination.
testByTissue() performs exact test for each tissue to
identify which tissues are significantly enriched in your input list
relative to the background:
testResult <- testByTissue(
result,
inclusion = "All",
padj = "BH",
secretoryOnly = FALSE
)
head(testResult)
#> tissue input_in input_total bg_in bg_total input_prop bg_prop
#> 1 Adipose tissue 21 815 50 2663 0.025766871 0.018775817
#> 2 Adrenal gland 11 815 45 2663 0.013496933 0.016898235
#> 3 Blood vessel 27 815 62 2663 0.033128834 0.023282013
#> 4 Bone marrow 37 815 169 2663 0.045398773 0.063462261
#> 5 Brain 71 815 327 2663 0.087116564 0.122793842
#> 6 Breast 5 815 25 2663 0.006134969 0.009387908
#> OR p_value p_adj
#> 1 1.3820520 0.25633632 0.7839794
#> 2 0.7960185 0.63317354 0.9857820
#> 3 1.4372644 0.12812944 0.6772556
#> 4 0.7019158 0.06177884 0.4571634
#> 5 0.6817824 0.00463354 0.1714410
#> 6 0.6514436 0.51653904 0.9857820Each row in the output corresponds to one tissue and contains:
| Column | Description |
|---|---|
tissue |
tissue name |
input_in |
input proteins expressed in this tissue |
input_total |
total input proteins |
bg_in |
background proteins expressed in this tissue |
bg_total |
total background proteins |
input_prop |
proportion of input proteins in tissue |
bg_prop |
proportion of background proteins in tissue |
OR |
odds ratio |
p_value |
exact test p-value |
p_adj |
adjusted p-value |
To restrict the analysis to secretory proteins only:
testPlot() generates a horizontal grouped bar chart
comparing input and background proportions across tissues, annotated
with p-values:
Blue bars show the proportion of input proteins expressed in each tissue; grey bars show the background proportion. P-values from exact test are annotated to the right of each tissue.
networkPlot() creates a bipartite network connecting
genes to their associated tissues, coloured by signal category:
In the network:
This is particularly useful for identifying groups of genes that share tissue associations.
goEnriched() performs Gene Ontology enrichment analysis
on genes showing tissue-specific expression in a tissue of interest:
# biological process enrichment for liver-associated genes
goResult <- goEnriched(
result,
type = "BP",
tissueTest = "Liver",
inclusion = "All"
)
# view top enriched terms
head(as.data.frame(methods::slot(goResult, "result")))
#> ID Description GeneRatio
#> GO:0010876 GO:0010876 lipid localization 8/51
#> GO:0006869 GO:0006869 lipid transport 7/51
#> GO:0006091 GO:0006091 generation of precursor metabolites and energy 6/51
#> GO:0005975 GO:0005975 carbohydrate metabolic process 7/51
#> GO:0019221 GO:0019221 cytokine-mediated signaling pathway 5/51
#> GO:0070371 GO:0070371 ERK1 and ERK2 cascade 5/51
#> BgRatio RichFactor FoldEnrichment oddsRatio zScore pvalue
#> GO:0010876 13/161 0.6153846 1.942685 3.906977 2.406335 0.02066865
#> GO:0006869 12/161 0.5833333 1.841503 3.340909 2.056847 0.04466949
#> GO:0006091 11/161 0.5454545 1.721925 2.800000 1.683804 0.09102668
#> GO:0005975 15/161 0.4666667 1.473203 2.028409 1.306367 0.15401954
#> GO:0019221 10/161 0.5000000 1.578431 2.282609 1.282071 0.17348017
#> GO:0070371 10/161 0.5000000 1.578431 2.282609 1.282071 0.17348017
#> p.adjust qvalue geneID
#> GO:0010876 1 1 PLA2G12B/APOF/CRP/PLA2G2A/APOB/GLTPD2/FABP1/SYT7
#> GO:0006869 1 1 PLA2G12B/APOF/PLA2G2A/APOB/GLTPD2/FABP1/SYT7
#> GO:0006091 1 1 LEPR/FBP1/UGP2/PPP1R3B/PDIA5/PYGL
#> GO:0005975 1 1 GSTO1/CHI3L1/FBP1/UGP2/PPP1R3B/PC/PYGL
#> GO:0019221 1 1 EPO/GREM2/LEPR/THPO/CCL16
#> GO:0070371 1 1 EPO/FGA/PLA2G2A/THPO/CHI3L1
#> Count
#> GO:0010876 8
#> GO:0006869 7
#> GO:0006091 6
#> GO:0005975 7
#> GO:0019221 5
#> GO:0070371 5The type argument accepts:
"BP" — Biological Process (default)"MF" — Molecular Function"CC" — Cellular Componentlibrary(Protein2Tissue)
# --- inputs ---
data("plasma_data", package = "Protein2Tissue")
myList <- plasma_data %>%
filter(Coefficient.Age > 0 & q.Age < 0.05) %>%
pull(UniqueSymbol) %>%
toupper()
# example background: Ensembl IDs representing the detectable proteome
myBackground <- toupper(plasma_data$UniqueSymbol)
# --- step 1: tissue enrichment ---
result <- tissueAnalysis(
input = myList,
background = myBackground,
typeKey = "Gene", # identifier type for input
typeKeyBg = "Gene", # identifier type for background
)
#> Warning: 143 protein(s) in the background list not found in the database and
#> have been removed.
#> Warning: 38 protein(s) in the input list not found in the database and have
#> been removed.
writeOutput(result,type = "csv","~/Enrichment_Results.csv")
#> Output written to: ~/Enrichment_Results.csv
# --- step 2: overview ---
plotProteinType(result)
# --- step 4: exact test ---
testResult <- testByTissue(result, padj = "BH")
# --- step 5: bar chart ---
testPlot(testResult)#Scenario 2: Tissue-Specific Expression Analysis of Differentially Expressed #Genes This package can also identify genes or proteins enriched in specified tissues from lists of differentially expressed genes (DEGs) derived from RNA‑seq data or differentially expressed proteins (DEPs) obtained from tissue‑specific proteomics experiments.
result2 <- tissueAnalysis2(
input = c("BRCA1", "EGFR", "ETDB",
"CCDC7", "TSPY9", "CCDC148"), #List of DEG/DEPs
typeKey = "Gene",
database = NULL, # NULL uses bundled HPA database
inclusion = "All",
secretoryOnly = FALSE,
tissueToTest = "Testis" # tissue name must match the database
)
#> All input proteins found in the database.The results can be written to disk by the write.csv()
function.
In addition to using the bundled Human Protein Atlas–derived tissue expression database, this package allows you to construct a custom tissue expression database from a gene‑by‑tissue average expression matrix. This is useful when working with user‑generated datasets, alternative expression atlases, or organism‑specific expression resources. Help we are using the gene-by-tissue average transcripts per million (TPM) matrix from GTEx bundled to this package as an example.
The geneClassification() function classifies genes or
proteins based on their tissue‑specific expression patterns. The input
expression matrix should be formatted with genes (or proteins) as rows
and tissues as columns.
# Example expression matrix (genes x tissues)
#Download pre-processing average tissue expression levels among tissues
url <- "https://raw.githubusercontent.com/ChrYang/DataSet/main/tissue_tpm_gtex.csv"
tissue_tpm_gtex <- read.csv(url, row.names=1)
# Classify tissue specificity using gene symbols
res <- geneClassification(
expression = tissue_tpm_gtex,
typeKey = "Ensembl",
min_expression = 1,
secretory_analysis = FALSE
)
head(res)Related tissues can be grouped prior to classification, allowing tissue specificity to be assessed at the designated group rather than the automatically ranked group by expression levels.
data("tissue_map")
# Classify genes using grouped tissues
res_grouped <- geneClassification(
expression = tissue_tpm_gtex,
tissue_groups = tissue_map,
typeKey = "Ensembl",
min_expression = 1,
secretory_analysis = FALSE
)The resulting classification output can be used directly as a custom
tissue expression database in downstream analyses, including tissue
enrichment testing with tissueAnalysis().
The bundled tissue expression database uses tissue-specific gene
expression data from the Human
Protein Atlas. If you use Protein2Tissue in your work,
please also cite the HPA:
Uhlen M et al. (2015). Tissue-based map of the human proteome. Science, 347(6220). https://doi.org/10.1126/science.1260419
Uhlen M et al. (2017). A pathology atlas of the human cancer transcriptome. Science, 357(6352). https://doi.org/10.1126/science.aan2507
GTEx Consortium (2013). The Genotype-Tissue Expression (GTEx) project. Nature Genetics, 45(6). https://doi.org/10.1038/ng.2653
sessionInfo()
#> R version 4.6.1 (2026-06-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 26.04.1 LTS
#>
#> Matrix products: default
#> BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.32.so; LAPACK version 3.12.0
#>
#> locale:
#> [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
#> [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
#> [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
#> [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
#> [9] LC_ADDRESS=C LC_TELEPHONE=C
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
#>
#> time zone: Etc/UTC
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] Protein2Tissue_0.99.6 ggplot2_4.0.3 dplyr_1.2.1
#> [4] BiocStyle_2.41.0
#>
#> loaded via a namespace (and not attached):
#> [1] RColorBrewer_1.1-3 sys_3.4.3 jsonlite_2.0.0
#> [4] tidydr_0.0.7 magrittr_2.0.5 ggtangle_0.1.4
#> [7] farver_2.1.2 rmarkdown_2.32 fs_2.1.0
#> [10] vctrs_0.7.3 memoise_2.0.1 ggtree_4.3.0
#> [13] rstatix_1.1.0 htmltools_0.5.9 BiocBaseUtils_1.15.1
#> [16] broom_1.0.13 Formula_1.2-6 gridGraphics_0.5-1
#> [19] sass_0.4.10 bslib_0.12.0 htmlwidgets_1.6.4
#> [22] plyr_1.8.9 httr2_1.3.0 rootSolve_1.8.2.4
#> [25] cachem_1.1.0 buildtools_1.0.0 igraph_2.3.4
#> [28] lifecycle_1.0.5 pkgconfig_2.0.3 Matrix_1.7-6
#> [31] R6_2.6.1 fastmap_1.2.0 gson_0.2.2
#> [34] digest_0.6.39 Exact_3.3 aplot_0.3.2
#> [37] enrichplot_1.99.8 ggnewscale_0.5.2 patchwork_1.3.2
#> [40] AnnotationDbi_1.75.2 S4Vectors_0.51.10 aisdk_1.4.12
#> [43] ps_1.9.3 RSQLite_3.53.3 org.Hs.eg.db_3.23.1
#> [46] ggpubr_1.0.0 labeling_0.4.3 abind_1.4-8
#> [49] httr_1.4.9 polyclip_1.10-7 compiler_4.6.1
#> [52] bit64_4.8.6 fontquiver_0.2.1 withr_3.0.3
#> [55] backports_1.5.1 S7_0.2.2 carData_3.0-6
#> [58] viridis_0.6.5 DBI_1.3.0 ggforce_0.5.0
#> [61] ggsignif_0.6.4 MASS_7.3-66 rappdirs_0.3.4
#> [64] tools_4.6.1 otel_0.2.0 ape_5.8-1
#> [67] scatterpie_0.2.6 glue_1.8.1 callr_3.8.0
#> [70] nlme_3.1-171 GOSemSim_2.39.4 grid_4.6.1
#> [73] cluster_2.1.8.3 reshape2_1.4.5 generics_0.1.4
#> [76] gtable_0.3.6 tidyr_1.3.2 car_3.1-5
#> [79] tidygraph_1.3.1 XVector_0.53.0 BiocGenerics_0.59.12
#> [82] ggrepel_0.9.8 pillar_1.11.1 stringr_1.6.0
#> [85] yulab.utils_0.2.5 splines_4.6.1 tweenr_2.0.3
#> [88] treeio_1.37.1 lattice_0.23-1 bit_4.6.0
#> [91] tidyselect_1.2.1 fontLiberation_0.1.0 GO.db_3.23.1
#> [94] maketools_1.3.2 Biostrings_2.81.9 knitr_1.52
#> [97] fontBitstreamVera_0.1.1 gridExtra_2.3.1 IRanges_2.47.5
#> [100] Seqinfo_1.3.2 stats4_4.6.1 xfun_0.62
#> [103] graphlayouts_1.2.5 Biobase_2.73.2 stringi_1.8.9
#> [106] lazyeval_0.2.3 ggfun_0.2.2 yaml_2.3.12
#> [109] evaluate_1.0.5 ggraph_2.2.2 gdtools_0.5.2
#> [112] tibble_3.3.1 qvalue_2.45.0 BiocManager_1.30.27
#> [115] ggplotify_0.1.4 cli_3.6.6 systemfonts_1.3.2
#> [118] processx_3.9.0 jquerylib_0.1.4 Rcpp_1.1.2
#> [121] png_0.1-9 parallel_4.6.1 blob_1.3.0
#> [124] clusterProfiler_4.21.4 DOSE_4.7.3 viridisLite_0.4.3
#> [127] tidytree_0.4.8 ggiraph_0.9.6 enrichit_0.2.6
#> [130] scales_1.4.0 purrr_1.2.2 crayon_1.5.3
#> [133] rlang_1.3.0 KEGGREST_1.53.6