We have developed scGATE (single-cell gene regulatory gate) as a logic-based model for deciphering tissue- and cell-type-specific gene regulatory networks from single-cell RNA sequencing (scRNA-seq). While previous efforts have focused on reconstructing directed transcription factor (TF) to target gene networks, logic-based models enable the exploration of more complex combinatorial relationships between regulators. In particular, Boolean logic models can capture higher-order TF interactions, represented through AND, OR, and XOR logic gates. Our novel approach infers TF-gene networks from scRNA-seq data while simultaneously elucidating the underlying Boolean logic that combines TF activities. The methodology integrates external genomic data, such as single-cell assay for transposase-accessible chromatin sequencing (scATAC-seq) and motif analysis, to narrow down candidate TFs for each target gene. TF-gene links are further refined using scRNA-seq data, and logic rules are derived. To enhance statistical power, scGATE focuses on reconstructing context specific regulatory networks, including tissue- or cell-type-specific networks. This study presents an integrative framework for deducing cell-type-specific gene regulation, moving beyond TF-gene pairs to capture the complex logic operations underlying combinatorial control.
Malekpour, S.A., Haghverdi, L., Sadeghi, M., Single-cell multi-omics analysis identifies context specific gene regulatory gates and mechanisms. Briefings in Bioinformatics 25 (3), 2024, bbae180.
If you find our study useful and relevant to your research, please kindly cite us. Your citation means a lot to us and helps acknowledge our contributions.
The scGATE codes are written in R version 4.1.3 and have been tested in both Windows and Linux environments.
Download the compiled package file
scGATE_0.1.0.tar.gzfrom this GitHub page.Install the scGATE package by running the following command in R:
install.packages("path/to/scGATE_0.1.0.tar.gz", repos=NULL, type="source")
Please ensure that you have the following packages installed:
install.packages("VGAM") install.packages("truncnorm")
install.packages("arrow")
install.packages("doParallel")
install.packages("foreach")
install.packages("doSNOW")In order to run scGATE with parallel computing, the packages doParallel, foreach, and doSNOW need to be installed.
To load the packages, use the following commands:
library(scGATE) library(VGAM) library(truncnorm) library(arrow) To summarize information in the base GRN file in ".parquet" format, previously generated using external hints like scATAC-seq and TF binding motif analyses, you can use the read_base_GRN() function from the scGATE package.
# Read and summarize base GRN filecandidate_tf_target<- as.data.frame(read_parquet("Buenrostro2018_base_GRN_dataframe.parquet"))
candidate_tf_target<- read_base_GRN(candidate_tf_target)To preprocess raw scRNA-seq data, including steps such as normalization and rescaling, you can use the scRNA_seq_preprocessing() function from the scGATE package.
# Preprocess scRNA-seq count datanormalized_counts<- scRNA_seq_preprocessing(data=data_scRNA_seq, library_size_normalization="True", tf_list=NA)Parameter Descriptions
# data The scRNA-seq raw data matrix with cells in rows and genes in columns.# library_size_normalization A flag indicating whether library size normalization should be performed.# The default value is "True".# Set it to "False" if you don't want to perform library size normalization.# tf_list A list of transcription factors (TFs) to consider.# The default value is NA, which means all columns in the data matrix will be considered as TFs. scGATE provides two functions for TF-target network inference: scGATE_gate() and scGATE_edge(). These functions infer the TF-target network with and without predicted Boolean logic gates in the output, respectively.
The scGATE_gate() function in the scGATE package is more suitable for small networks or when the base gene regulatory network (GRN) is available from external sources such as scATAC-seq and TF motif data.
To infer the TF-target network with logic gates in the output, you can use the scGATE_gate() function.
# Infer TF-target network without logic gates in the outputgates<- scGATE_logic(data=data, base_GRN=NA, h_set=NA, number_of_em_iterations=NA, max_num_regulators=NA, abs_cor=NA, top_gates=NA, run_mode=NA)
print(head(gates))Parameter Descriptions
# data A gene expression matrix with normalized counts within the (0,1) interval,# where samples are represented as rows and genes as columns.# The gene expression matrix should have been preprocessed using the scRNA_seq_preprocessing() function.# base_GRN Base TF-gene interaction network derived from external hints# (e.g., scATAC-seq data and TF binding site motifs on DNA).# Leave it empty if no base GRN is available.# h_set The range of possible values for the "h" parameter in the Hill climbing function.# number_of_em_iterations The number of iterations in the expectation-maximization (EM) algorithm.# The default value is 3.# max_num_regulators Maximum number of TFs in a logic gate that can regulate the target gene profile.# The default value is 3.# abs_cor This parameter varies in the (0, 1) interval and further removes edges with low absolute Pearson correlations between TFs and their targets.# A (default) value of 0 indicates no filtration based on correlations.# top_gates The number of top Boolean logic gates to be reported for each target gene, based on Bayes Factor.# The default value is 1.# run_mode Use "simple" for a faster algorithm run and "complex" for more precise results that take more time.# The argument is relevant to the possible complexities in the hill function parameter space for regulatory TFs and target genes.# The default value is "simple".# weight_threshold The output form scGATE will present the logic combination or partition that yields a certain percentage of the target gene,# specifically when it is above the weight_threshold.# The default value is 0.05.# num_cores Specify the number of parallel workers (adjust according to your system).To infer the TF-target network without logic gates in the output, you can use the scGATE_edge() function.
# Infer TF-target network without logic gates in the outputedges<- scGATE_edge(data=data, base_GRN=candidate_tf_target, h_act=NA, number_of_em_iterations=NA, max_num_regulators=NA, abs_cor=NA)
print(head(edges))Parameter Descriptions
# data A gene expression matrix with normalized counts within the (0,1) interval,# where samples are represented as rows and genes as columns.# The gene expression matrix should have been preprocessed using the scRNA_seq_preprocessing() function.# base_GRN Base TF-gene interactions derived from external hints# (e.g., scATAC-seq data and TF binding site motifs on DNA).# Leave it empty if no base GRN is available.# h_act Parameter of the Hill climbing function.# It is the hill coefficient that represents the cooperativity or sigmoidicity of the TF regulatory response.# The default value is 7.# number_of_em_iterations The number of iterations in the expectation-maximization (EM) algorithm.# The default value is 3.# max_num_regulators Maximum number of TFs in a logic gate that can regulate the target gene profile.# The default value is 3.# abs_cor This parameter varies in the (0, 1) interval and further removes edges with low absolute Pearson correlations between TFs and their targets.# A (default) value of 0 indicates no filtration based on correlations.# num_cores Specify the number of parallel workers (adjust according to your system) # 1. Please refer to the Jupyter notebook for instructions on how to perform Louvain clustering on the cells in the BoolODE simulated data.# 2. Retrieve the data from Cluster I of cells, which was obtained in the previous step.# Load scGATE package and data in example_data folder
rm(list= ls())
library(scGATE)
data<- as.matrix(read.csv("/example_data/ClusterI.csv")[ ,2:15])
print(head(data))
gAgBgCgC1gC2gDgD1gD2gEgE1gE2gFgF1gF2
[1,] 0.027646772.0289440.016885770.019465260.023807720.018528240.020698950.020931841.9321680.068895331.8244970.049631500.057944130.04217521
[2,] 0.026439862.0279560.017308820.019630090.024591900.018348000.019093000.020506921.9656280.060752941.8293490.046244830.044058360.02271849
[3,] 0.025937492.0335920.017299840.017962690.024223720.017605210.019063450.021258641.9768880.045145801.8173910.031753140.037384650.02141319
[4,] 0.025958852.0199710.017568620.017871570.024127550.017916440.021124350.021061851.9807590.037202931.8369620.020330920.036776510.01974638
[5,] 0.026298852.0154610.017536450.019212520.024913280.019094650.021010080.021329061.9868720.037385541.8372260.019997040.036832520.01955996
[6,] 0.026402932.0093880.017483220.020283040.024495850.019900730.020962720.020651111.9822860.037761441.8344060.022269780.036581670.01937109# 3. data preprocessing # For scGATE simulated data, library size normalization is not performed. # However, the simulated data is only re-scaled using the quantile normalization technique to fit the data within the (0,1) interval.data<- scRNA_seq_preprocessing(data=data, library_size_normalization="False")# 4. Remove genes with low variability (scGATE operates on highly variable genes per context).# This step is optionaldata$n_counts<-data$n_counts[ , which(sqrt(apply(data$n_counts,2,var))>0.20)]# 5. Run scGATE_logic() function# Please note that the likelihood values can be affected by the Louvain clustering results.gates<- scGATE_logic(data=data, top_gates=1, run_mode="simple")
print(head(gates))
gene_name-log10L0-log10L1log10BFlogic_gate1gE173.9-268.57442.47~gF2gE151.85-234.65286.50gE.~gE23gE238.43-235.48273.91gE.~gE14gF170.38-278.57448.95~gE5gF180.36-215.32295.68gF.~gF26gF267.6-217.88285.48gF.~gF1# 1. Please refer to the Jupyter notebook for instructions on how to perform Louvain clustering on the cells in the mouse haematopoiesis scRNA-seq dataset.# 2. Retrieve the data from Megakaryocyte cells (Cluster 11).# Load scGATE package and data in example_data folder
rm(list= ls())
library(scGATE)
data<- as.data.frame(read.csv("/example_data/subset_counts_cluster_11.csv" , header=TRUE))
# select genes involved in the MegE differentiationgene_list<- c("Gata1", "Fli1", "Klf1", "Spi1", "Zfpm1", "Tal1", "Gata2")
data<-data[ , gene_list]
data<- na.omit(data)
print(head(data))
Gata1Fli1Klf1Spi1Zfpm1Tal1Gata210.69314721.09861230.0000000.69314720.00000000.69314720.000000020.00000001.38629440.0000000.00000000.00000000.69314721.098612330.69314721.60943800.0000000.00000000.00000000.00000000.693147240.00000000.00000001.0986120.00000000.69314720.00000001.609438050.00000000.00000000.0000000.00000000.69314720.69314721.386294460.00000000.69314720.0000000.00000000.69314721.09861230.0000000# Load base GRNbase_GRN<- read.csv("/example_data/base_grn_mouse_blood_cell_differentiation_toggle_switch.csv")# 3. data preprocessing # The dataset underwent library size normalization in Jupyter Notebook. To fit the scRNA-seq data within the (0,1) interval, we applied quantile normalization as a technique to rescale the data.data<- scRNA_seq_preprocessing(data=data, library_size_normalization="False")# 4. Run scGATE_logic() functiongates<- scGATE_logic(data=data, base_GRN=base_GRN, number_of_em_iterations=10, top_gates=1, run_mode="complex")
print(head(gates))
# To effectively derive Boolean rules from extensive scRNA-seq datasets containing over 10 TFs,# we recommend employing scGATE with the following configuration.gates<- scGATE_logic(data=data, base_GRN=base_GRN, number_of_em_iterations=10, top_gates=50, run_mode="simple")
print(gates)
# or you may use,h_set<- c(1.25, 2.25)
gates<- scGATE_logic(data=data, base_GRN=base_GRN, h_set=h_set, number_of_em_iterations=10, max_num_regulators=2, top_gates=50, run_mode="complex")
print(gates)# 1. Please refer to the Jupyter notebook for instructions on how to perform scATAC-seq analysis to derive the candidate TF lists (base GRNs) in *.parquet file format.# 2. Load scGATE package and data (base GRN and scRNA-seq data and TF list) in example_data folder
rm(list=ls())
library(scGATE)
library(arrow)
# Load base GRN derived from external hintscandidate_tf_target<- as.data.frame(read_parquet("/example_data/Cusanovich2018_Spleen_peak_base_GRN_dataframe.parquet"))
candidate_tf_target<- read_base_GRN(candidate_tf_target)
# Load scRNA-seq datadata<- as.data.frame(read.csv("/example_data/Tabula_Muris2018_Spleen-10X_P4_7_ExpressionData.csv" , header=TRUE))
gene_names<-data[ ,1]
data<- t(data[ ,2:ncol(data)])
colnames(data) <-gene_names
head(data[ , 1:10])
BatfStat5bCtcfH2-Eb1AW112010Ly6dRplp0Id2Dok2Gimap3AAACCTGAGAAGGACA.1000180010000AAACCTGAGCTAAGAT.100101905111AAACCTGCAACAACCT.1000220512002AAACCTGCAGCCAATT.1000141521001AAACCTGCAGCTCCGA.1001301264000AAACCTGTCAGGTAAA.1000233824000# Load TF list# This step is optionaltf_names<- unlist(read.table("/example_data/Tabula_Muris2018_Spleen-10X_P4_7_tf_lists.txt"))
print(head(tf_names))
V1V2V3"Batf""Stat5b""Ctcf"# 3. scRNA-seq data preprocessing (library size normalization, quantile normalization technique to fit the scRNA-seq data within the (0,1) interval) data<- scRNA_seq_preprocessing(data=data, library_size_normalization="True", tf_list=tf_names)# 4. Run scGATE_edge() functionranked_edge_list<- scGATE_edge(data=data, base_GRN=candidate_tf_target, h_act=7)
print(head(ranked_edge_list))
fromtoBF_score1CtcfRps192002.4192BatfRps192001.3883Stat5bRplp01840.0464CtcfRplp01839.6105CtcfRpl361639.9106CtcfEif5a1550.267# 1. Please refer to the Jupyter notebook for instructions on how to perform scATAC-seq analysis to derive the candidate TF lists (base GRNs) in *.parquet file format.# 2. Load scGATE package and data (base GRN and scRNA-seq data and TF list) in example_data folder
rm(list=ls())
library(scGATE)
# Load base GRN derived from external hintscandidate_tf_target<- as.data.frame(read_parquet("/example_data/Buenrostro2018_base_GRN_dataframe.parquet"))
candidate_tf_target<- read_base_GRN(candidate_tf_target)
# Load scRNA-seq datadata<- as.data.frame(read.csv("/example_data/Buenrostro2018_ExpressionData.csv" , header=TRUE))
gene_names<-data[ ,1]
data<- t(data[ ,2:ncol(data)])
colnames(data) <-gene_names
head(data[ , 1:10])
IRF8FOSMAFFSPI1JUNBSPIBIRF7TFDP1GATA1RAD21hsc_10200200001hsc_20670300001hsc_30200500002hsc_40600100101hsc_50152100000hsc_60300100000# Load TF list# This step is optionaltf_names<- unlist(read.table("/example_data/Buenrostro2018_tf_lists.txt"))
print(head(tf_names))
V1V2V3V4V5V6"IRF8""FOS""MAFF""SPI1""JUNB""SPIB"# 3. scRNA-seq data preprocessing (library size normalization, quantile normalization technique to fit the scRNA-seq data within the (0,1) interval)data<- scRNA_seq_preprocessing(data=data, library_size_normalization="True", tf_list=tf_names)# 4. Run scGATE_edge() functionranked_edge_list<- scGATE_edge(data=data, base_GRN=candidate_tf_target, h_act=7)
print(head(ranked_edge_list))
fromtoBF_score1E2F1MALAT113094.062BHLHE40MALAT113094.053TFDP1MALAT113093.974NFE2MALAT113092.805IRF8MALAT113091.926E2F1PTMA11204.92Raw scRNA-seq data for cell-type specific logic gate inference in the mouse haematopoiesis dataset (Fig.3) is also available at Zenodo https://doi.org/10.5281/zenodo.8353409.
The base GRNs reconstructed with scATAC-seq and TF binding site motif, in mouse tissue and human haematopoiesis datasets, together with other intermediate and processed files are available at Zenodo https://doi.org/10.5281/zenodo.8353409.
