PyOVERCAST 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
@@ -0,0 +1,86 @@
1
+ Metadata-Version: 2.4
2
+ Name: PyOVERCAST
3
+ Version: 1.0.0
4
+ Summary: A Python package for mining key transcription factors from transcriptome data.
5
+ Author-email: Tinghua Huang <thua45@126.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/thua45/PyOVERCAST
8
+ Project-URL: Documentation, https://github.com/thua45/PyOVERCAST#readme
9
+ Project-URL: Repository, https://github.com/thua45/PyOVERCAST
10
+ Project-URL: Issues, https://github.com/thua45/PyOVERCAST/issues
11
+ Keywords: PyOVERCAST,Transcription Factor,Binding Site,Transcriptome Data
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Requires-Python: >=3.11
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: numpy==1.26; sys_platform == "darwin"
21
+ Requires-Dist: numpy>=2.0; sys_platform == "win32"
22
+ Requires-Dist: numpy>=2.0; sys_platform == "linux"
23
+ Requires-Dist: pandas==3.0; sys_platform == "darwin"
24
+ Requires-Dist: pandas>=3.0; sys_platform == "win32"
25
+ Requires-Dist: pandas>=3.0; sys_platform == "linux"
26
+ Requires-Dist: statsmodels==0.14; sys_platform == "darwin"
27
+ Requires-Dist: statsmodels>=0.14; sys_platform == "win32"
28
+ Requires-Dist: statsmodels>=0.14; sys_platform == "linux"
29
+ Requires-Dist: seaborn==0.13; sys_platform == "darwin"
30
+ Requires-Dist: seaborn>=0.13; sys_platform == "win32"
31
+ Requires-Dist: seaborn>=0.13; sys_platform == "linux"
32
+ Requires-Dist: matplotlib==3.11; sys_platform == "darwin"
33
+ Requires-Dist: matplotlib>=3.11; sys_platform == "win32"
34
+ Requires-Dist: matplotlib>=3.11; sys_platform == "linux"
35
+ Provides-Extra: dev
36
+ Requires-Dist: matplotlib; extra == "dev"
37
+ Provides-Extra: test
38
+ Requires-Dist: matplotlib; extra == "test"
39
+ Dynamic: license-file
40
+
41
+ # PyOVERCAST
42
+
43
+ A Python package for mining key transcription factors from transcriptome data.
44
+
45
+ ## Installation
46
+
47
+ ```bash
48
+ pip install numpy pandas statsmodels seaborn matplotlib PyOVERCAST
49
+ ```
50
+
51
+ ## Usage
52
+
53
+ ```python
54
+ from PyOVERCAST import clinks, predict
55
+
56
+ if __name__ == '__main__':
57
+ # download TF-target set, only need to run once!!!
58
+ clinks.download_data()
59
+
60
+ # list available TF-target set
61
+ sets_names = clinks.get_sets(species='Homo sapiens')
62
+ print(sets_names)
63
+
64
+ # list avaiable TFs
65
+ tfs_codes = clinks.get_tfs(set_name='human_hocomoco_CLink_wtcoor_1w_0.8')
66
+ print(tfs_codes)
67
+
68
+ # get targets
69
+ targets = clinks.get_targets(set_name='human_hocomoco_CLink_wtcoor_1w_0.8', tf='NFKB1_HUMAN.H11MO.1.B')
70
+ print(targets)
71
+
72
+ # predict one DEG-list
73
+ result = predict.olcr(set_names=['human_hocomoco_CLink_wtcoor_1w_0.8', 'human_jaspar_CLink_wtcoor_1w_0.8'], list_file='./PyOVERCAST_data/input_deg-list.txt', win=30, thread_n=16)
74
+
75
+ # or predict one DEG-list with bootstrap
76
+ result = predict.olcr_bootstrap(set_names=['human_hocomoco_CLink_wtcoor_1w_0.8', 'human_jaspar_CLink_wtcoor_1w_0.8'], list_file='./PyOVERCAST_data/input_deg-list.txt', win=30, thread_n=16)
77
+
78
+ # save result to text file
79
+ result.to_csv('output.txt', sep='\t', index=False, encoding='utf-8-sig')
80
+
81
+ # plot OLC matrix
82
+ predict.plot_olc(set_names=['human_hocomoco_CLink_wtcoor_1w_0.8', 'human_jaspar_CLink_wtcoor_1w_0.8'], list_file='./PyOVERCAST_data/input_deg-list.txt', tf='MA0844.2_XBP1', win=30)
83
+
84
+ # plot fitted 3D U-surface
85
+ predict.plot_fit3D(set_names=['human_hocomoco_CLink_wtcoor_1w_0.8', 'human_jaspar_CLink_wtcoor_1w_0.8'], list_file='./PyOVERCAST_data/input_deg-list.txt', tf='MA0844.2_XBP1', win=30)
86
+ ```
File without changes
@@ -0,0 +1,177 @@
1
+ # from importlib import resources
2
+ import urllib.request
3
+ import zipfile
4
+ import os
5
+ from pathlib import Path
6
+
7
+ overcast_data_dir = './OVERCAST_data'
8
+
9
+ def download_with_progress(url, filename=None):
10
+ """
11
+ 带进度显示的下载函数
12
+ """
13
+ def progress_callback(block_num, block_size, total_size):
14
+ """
15
+ 进度回调函数
16
+
17
+ Args:
18
+ block_num: 当前已下载的块数量
19
+ block_size: 每个块的大小(字节)
20
+ total_size: 文件总大小(字节)
21
+ """
22
+ downloaded = block_num * block_size
23
+ percent = downloaded / total_size * 100 if total_size > 0 else 0
24
+
25
+ # 限制显示频率,避免刷新太快
26
+ if block_num % 100 == 0 or downloaded >= total_size:
27
+ print(f"\rProgress: {percent:.1f}% ({downloaded}/{total_size} bytes)", end='', flush=True)
28
+
29
+ # 如果没有指定文件名,从URL中提取
30
+ if filename is None:
31
+ filename = os.path.basename(url)
32
+
33
+ print(f"start download: {url}")
34
+ print(f"save as: {filename}")
35
+
36
+ try:
37
+ urllib.request.urlretrieve(url, filename, progress_callback)
38
+ print("donwload sucessful")
39
+ except Exception as e:
40
+ print(f"donwload failed: {e}")
41
+ exit(1)
42
+
43
+ # 使用示例
44
+ # download_with_progress("https://example.com/largefile.zip", "downloaded_file.zip")
45
+
46
+ def extractall_individual_files(zip_path, extract_path):
47
+ """
48
+ 使用 extract() 方法逐个解压文件,确保覆盖
49
+ """
50
+ os.makedirs(extract_path, exist_ok=True)
51
+
52
+ with zipfile.ZipFile(zip_path, 'r') as zip_ref:
53
+ # 获取所有成员信息
54
+ members = zip_ref.infolist()
55
+
56
+ print(f"extracting {len(members)} file...")
57
+
58
+ for i, member in enumerate(members, 1):
59
+ try:
60
+ # 直接使用 extract() 方法,它会处理覆盖
61
+ zip_ref.extract(member, extract_path)
62
+
63
+ if i % 10 == 0 or i == len(members):
64
+ print(f"progress: {i}/{len(members)}")
65
+
66
+ except Exception as e:
67
+ print(f"extracting failed {member.filename}: {e}")
68
+ exit(1)
69
+
70
+ print("extracting finished")
71
+
72
+ # 使用示例
73
+ # extractall_individual_files("example.zip", "extracted_files")
74
+
75
+ def download_and_extract_zip(url, extract_to):
76
+ """
77
+ 下载ZIP文件并解压到指定目录
78
+
79
+ Args:
80
+ url: ZIP文件的URL
81
+ extract_to: 解压目标目录
82
+ """
83
+ # 创建目标目录
84
+ Path(extract_to).mkdir(parents=True, exist_ok=True)
85
+
86
+ # 临时ZIP文件路径
87
+ zip_path = os.path.join(extract_to, "temp.zip")
88
+
89
+ try:
90
+ # 下载文件
91
+ # print(f"downloading: {url}")
92
+ # urllib.request.urlretrieve(url, zip_path)
93
+ download_with_progress(url, zip_path)
94
+ # print("donwload finished")
95
+
96
+ # 解压文件
97
+ # print(f"extracting: {extract_to}")
98
+ # with zipfile.ZipFile(zip_path, 'r') as zip_ref:
99
+ # zip_ref.extractall(extract_to, overwrite=True)
100
+ extractall_individual_files(zip_path, extract_to)
101
+ # print("extract finished")
102
+
103
+ except Exception as e:
104
+ print(f"错误: {e}")
105
+ return False
106
+ finally:
107
+ # 清理临时ZIP文件
108
+ if os.path.exists(zip_path):
109
+ os.remove(zip_path)
110
+ print("clearing temp files")
111
+
112
+ return True
113
+
114
+ def download_data(data_dir=None):
115
+ if data_dir == None:
116
+ data_dir = overcast_data_dir
117
+ if not (os.path.exists(data_dir) and os.path.isdir(data_dir)):
118
+ print(data_dir, 'not exist, creating...')
119
+ folder_path = Path(data_dir)
120
+ folder_path.mkdir(exist_ok=True)
121
+ url = "http://www.thua45.cn/overcast/OVERCAST_data.zip"
122
+ extract_dir = data_dir
123
+ # extract_dir = "./downloaded_content"
124
+ success = download_and_extract_zip(url, extract_dir)
125
+ if success:
126
+ print("models installed successful")
127
+
128
+ def get_sets(species=None, data_dir=None):
129
+ if data_dir == None:
130
+ data_dir = overcast_data_dir
131
+ index_file = data_dir + '/sets_index.txt'
132
+ if not os.path.exists(index_file):
133
+ print('sets_index.txt not exist, you may need to run download_data() first')
134
+ exit(1)
135
+ header = ''
136
+ result = []
137
+ for line in open(index_file, 'r'):
138
+ if line[0] == "#":
139
+ header = line.rstrip()
140
+ continue
141
+ lblocks = line.rstrip().split('\t')
142
+ if species != None and lblocks[1] != species:
143
+ continue
144
+ result.append(lblocks[0])
145
+ return result
146
+
147
+ def get_tfs(set_name=None, data_dir=None):
148
+ if data_dir == None:
149
+ data_dir = overcast_data_dir
150
+ sets_file = data_dir + '/TF-target_sets/' + set_name + '.txt'
151
+ if not os.path.exists(sets_file):
152
+ print('sets_file not exist, you may need to run download_data() first')
153
+ exit(1)
154
+ result = set()
155
+ for line in open(sets_file, 'r'):
156
+ if line[0] == "#":
157
+ continue
158
+ lblocks = line.rstrip().split('\t')
159
+ result.add(lblocks[0])
160
+ return list(result)
161
+
162
+ def get_targets(set_name=None, tf=None, data_dir=None):
163
+ if data_dir == None:
164
+ data_dir = overcast_data_dir
165
+ sets_file = data_dir + '/TF-target_sets/' + set_name + '.txt'
166
+ if not os.path.exists(sets_file):
167
+ print('sets_file not exist, you may need to run download_data() first')
168
+ exit(1)
169
+ result = set()
170
+ for line in open(sets_file, 'r'):
171
+ if line[0] == "#":
172
+ continue
173
+ lblocks = line.rstrip().split('\t')
174
+ if tf != None and lblocks[0] != tf:
175
+ continue
176
+ result.add(lblocks[1])
177
+ return list(result)
@@ -0,0 +1,631 @@
1
+ #!/usr/bin/env python
2
+ import os
3
+ import math
4
+ import time
5
+ from collections import defaultdict
6
+ from operator import itemgetter
7
+ import numpy as np
8
+ import pandas as pd
9
+ import matplotlib.pyplot as plt
10
+ import statsmodels.api as sm
11
+ # 设置中文字体,避免 DejaVu Sans 缺失中文字符
12
+ plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'PingFang SC', 'Noto Sans CJK SC', 'Arial Unicode MS'] # 指定默认字体
13
+ plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
14
+ import multiprocessing as mp
15
+ import seaborn as sns
16
+
17
+ overcast_data_dir = './OVERCAST_data'
18
+
19
+ def read_tfbs_file(file, tfbs):
20
+ for line in open(file, 'r'):
21
+ if line[0] == '#':
22
+ continue
23
+ lblocks = line.rstrip().split('\t')
24
+ tfbs[lblocks[0]]['gene'].append(lblocks[1])
25
+ tfbs[lblocks[0]]['LogFC'].append(float(lblocks[2]))
26
+
27
+ def read_gene_sets(files):
28
+ tfbs = defaultdict(lambda: defaultdict(list))
29
+ for file in files:
30
+ read_tfbs_file(file, tfbs)
31
+ tfbs_array = []
32
+ tfs = list(tfbs.keys())
33
+ for tf in tfs:
34
+ df = pd.DataFrame({"gene": tfbs[tf]['gene'], "logFC": tfbs[tf]['LogFC']}, index=tfbs[tf]['gene'])
35
+ tfbs_array.append([tf, df])
36
+ return tfbs_array
37
+
38
+ def read_DEG_list(file_in):
39
+ genes = []
40
+ LogFCs = []
41
+ #file_in = 'XBP1_DEG-list.txt'
42
+ for line in open(file_in, 'r'):
43
+ if line[0] == '#':
44
+ continue
45
+ lblocks = line.rstrip().split('\t')
46
+ genes.append(lblocks[0])
47
+ LogFCs.append(float(lblocks[1]))
48
+ df = pd.DataFrame({"gene": genes, "logFC": LogFCs}, index=genes)
49
+ return df
50
+
51
+ def slide_window_inclusive(lst, w, s):
52
+ lst_splits = []
53
+ l_idxs = []
54
+ n = len(lst)
55
+ for start in range(0, n, s):
56
+ lst_splits.append(lst[start:min(start + w, n)])
57
+ l_idxs.append(start + math.floor(min(w, n - start) / 2.0))
58
+ return l_idxs, lst_splits
59
+
60
+ def rrho_matrix_str(list1, list2, window=20, universe=None):
61
+ # unique genes preserving order
62
+ list1 = list(dict.fromkeys([str(x) for x in list1]))
63
+ list2 = list(dict.fromkeys([str(x) for x in list2]))
64
+
65
+ l_idxs1, lst_splits1 = slide_window_inclusive(list1, math.floor(len(list1) / window), math.floor(len(list1) / window / 3.0))
66
+ l_idxs2, lst_splits2 = slide_window_inclusive(list2, math.floor(len(list2) / window), math.floor(len(list2) / window / 3.0))
67
+ step = math.floor(window / 3)
68
+
69
+ mat = np.zeros((len(l_idxs1), len(l_idxs2)), dtype=float)
70
+ # print(mat.shape)
71
+ mi = -1
72
+ for lst_i in lst_splits1:
73
+ mi += 1
74
+ mj = -1
75
+ for lst_j in lst_splits2:
76
+ mj += 1
77
+ mat[mi, mj] = len(set(lst_i) & set(lst_j))
78
+
79
+ # mat = mat - np.mean(mat)
80
+ rrho_df = pd.DataFrame(mat, index=l_idxs1, columns=l_idxs2)
81
+ rrho_df.index.name = "Prefix_list1"
82
+ rrho_df.columns.name = "Prefix_list2"
83
+ return rrho_df
84
+
85
+ def Z_to_frame(Z):
86
+ # ============================
87
+ # 1. 生成模拟数据(网格点云)
88
+ # ============================
89
+ # 假设正方形边长为2,范围[-1, 1],生成20x20网格
90
+ np.random.seed(42) # 固定随机种子,保证可复现
91
+ x = np.linspace(-1, 1, Z.shape[1])
92
+ y = np.linspace(-1, 1, Z.shape[0])
93
+ X, Y = np.meshgrid(x, y)
94
+
95
+ # 展平成一维数组,便于回归
96
+ df = pd.DataFrame({
97
+ 'x': X.ravel(),
98
+ 'y': Y.ravel(),
99
+ 'z': Z.ravel()
100
+ })
101
+
102
+ return df
103
+
104
+ def compute_dtci_core(df, x_col='x', y_col='y', z_col='z',
105
+ c=1.0, alpha=1.0, beta_w=0.5, gamma=1.0):
106
+ """
107
+ 核心DTCI计算 —— 使用 statsmodels.OLS
108
+
109
+ 拟合模型: z = β0 + β1·x + β2·y + β3·(x·y) + ε
110
+
111
+ 参数:
112
+ df: DataFrame,包含 x, y, z 列
113
+ x_col, y_col, z_col: 列名
114
+ c: 深度调节系数
115
+ alpha, beta_w, gamma: DI, SI, QI 的权重指数
116
+
117
+ 返回:
118
+ DTCI, beta_hat, R2_adj, p_beta3, residuals
119
+ """
120
+ x = df[x_col].values
121
+ y = df[y_col].values
122
+ z = df[z_col].values
123
+ xy = x * y
124
+
125
+ # 使用 statsmodels.OLS(自动处理常数项、标准误和p值)
126
+ X_design = sm.add_constant(pd.DataFrame({'x': x, 'y': y, 'xy': xy}))
127
+ model = sm.OLS(z, X_design).fit()
128
+
129
+ # 提取系数 [const, x, y, xy]
130
+ beta_hat = model.params.values
131
+ beta0, beta1, beta2, beta3 = beta_hat
132
+
133
+ # 模型质量
134
+ R2 = model.rsquared
135
+ R2_adj = model.rsquared_adj
136
+
137
+ # 系数显著性(statsmodels 自动计算,更准确)
138
+ p_values = model.pvalues.values
139
+
140
+ # 数据波动
141
+ z_std = np.std(z, ddof=1)
142
+
143
+ # 子指标
144
+ DI = np.abs(beta3) / (np.abs(beta3) + c * z_std)
145
+ SI = min(1.0, -np.log10(max(p_values[3], 1e-10)) / 25.0)
146
+ QI = max(0.0, R2_adj)
147
+
148
+ total_weight = alpha + beta_w + gamma
149
+ DTCI = (DI**alpha * SI**beta_w * QI**gamma) ** (1.0 / total_weight)
150
+
151
+ return DTCI, beta_hat, R2_adj, p_values[3], model.resid
152
+
153
+ def bootstrap_parametric_h0(df, n_bootstrap=2000, random_state=42):
154
+ """
155
+ 参数化Bootstrap:在H0(无对角线趋势,即beta3=0)下生成数据
156
+
157
+ 步骤:
158
+ 1. 在H0下拟合模型:z = beta0 + beta1·x + beta2·y + eps
159
+ 2. 获取拟合值和残差
160
+ 3. 从残差中有放回抽样,构造新数据
161
+ 4. 对新数据计算DTCI
162
+ 5. 比较观测DTCI与零分布,计算p值
163
+ """
164
+ np.random.seed(random_state)
165
+ n = len(df)
166
+ x = df['x'].values
167
+ y = df['y'].values
168
+ z = df['z'].values
169
+
170
+ # 步骤1:在H0下拟合(不含交互项)
171
+ X_h0 = sm.add_constant(pd.DataFrame({'x': x, 'y': y}))
172
+ model_h0 = sm.OLS(z, X_h0).fit()
173
+ z_pred_h0 = model_h0.fittedvalues
174
+ resid_h0 = model_h0.resid
175
+
176
+ # 观测DTCI(全模型)
177
+ # dtci_obs = dtci_compute_dtci_core(df)[0]
178
+ dtci_obs, beta_hat, dtci_pval = itemgetter(0, 1, 3)(compute_dtci_core(df))
179
+
180
+ # 步骤3-4:生成零分布
181
+ dtci_null = []
182
+ for i in range(n_bootstrap):
183
+ resid_boot = np.random.choice(resid_h0, size=n, replace=True)
184
+ z_boot = z_pred_h0 + resid_boot
185
+
186
+ df_boot = pd.DataFrame({'x': x, 'y': y, 'z': z_boot})
187
+ try:
188
+ dtci_i, _, _, _, _ = compute_dtci_core(df_boot)
189
+ dtci_null.append(dtci_i)
190
+ except:
191
+ pass
192
+
193
+ dtci_null = np.array(dtci_null)
194
+
195
+ # 步骤5:计算p值 (H1: DTCI > 0)
196
+ p_value = np.mean(dtci_null >= dtci_obs)
197
+
198
+ return {
199
+ 'method': '参数化Bootstrap (H0: beta3=0)',
200
+ 'dtci_obs': dtci_obs,
201
+ 'dtci_pval': dtci_pval,
202
+ 'beta3': beta_hat[3],
203
+ 'dtci_null': dtci_null,
204
+ 'p_value': p_value,
205
+ 'se_null': np.std(dtci_null, ddof=1),
206
+ 'mean_null': np.mean(dtci_null),
207
+ 'n_boot': len(dtci_null)
208
+ }
209
+
210
+ def rrho_coor(df1, df2, win):
211
+ gene_col1 = df1.columns[0]
212
+ score_col1 = df1.columns[1]
213
+ df1 = df1.sort_values(score_col1, ascending=False)
214
+ genes1 = df1[gene_col1].astype(str).tolist()
215
+
216
+ # remove duplicates while preserving order
217
+ genes1 = list(dict.fromkeys(genes1))
218
+
219
+ gene_col2 = df1.columns[0]
220
+ score_col2 = df2.columns[1]
221
+ df2 = df2.sort_values(score_col2, ascending=False)
222
+ genes2 = df2[gene_col2].astype(str).tolist()
223
+ # remove duplicates while preserving order
224
+ genes2 = list(dict.fromkeys(genes2))
225
+
226
+ window = win
227
+ if (len(genes1) < window*3 or len(genes2) < window*3):
228
+ return 0.0, 1.0, 0.0
229
+ rrho_df = rrho_matrix_str(genes1, genes2, window=window)
230
+
231
+ if rrho_df.shape[0] == 0 or rrho_df.shape[1] == 0 or (rrho_df > 0.0).sum().sum() == 0:
232
+ return 0.0, 1.0, 0.0
233
+
234
+ #beta_xy, pval_xy = td_coor(rrho_df.to_numpy())
235
+ df = Z_to_frame(rrho_df.to_numpy())
236
+ DTCI, betas, pval_xy = itemgetter(0, 1, 3)(compute_dtci_core(df))
237
+
238
+ return betas[3], pval_xy, DTCI
239
+
240
+ def plot_rrho(rrho_df, out_file=None, title="RRLO Matrix", cmap="magma"):
241
+ """
242
+ Plot RRHO heatmap.
243
+ """
244
+ plt.figure(figsize=(6, 5), dpi=150)
245
+ ax = sns.heatmap(
246
+ rrho_df,
247
+ cmap=cmap,
248
+ #cbar_kws={"label": r"$-\log_{10}(p)$"},
249
+ cbar_kws={"label": r"Overlaps"},
250
+ xticklabels=max(1, len(rrho_df.columns) // 10),
251
+ yticklabels=max(1, len(rrho_df.index) // 10),
252
+ )
253
+ ax.invert_yaxis() # 添加这一行,让 [0,0] 位于左下角
254
+ ax.set_xlabel("Prefix overlap in TF-target set")
255
+ ax.set_ylabel("Prefix overlap in DEG list")
256
+ ax.set_title(title, fontsize=10)
257
+ plt.tight_layout()
258
+
259
+ if out_file:
260
+ plt.savefig(out_file + '.pdf', dpi=300, bbox_inches="tight")
261
+ plt.savefig(out_file + '.svg', dpi=300, bbox_inches="tight")
262
+ plt.show()
263
+
264
+ def plot_olc_plot(df1, df2, win):
265
+ gene_col1 = df1.columns[0]
266
+ score_col1 = df1.columns[1]
267
+ df1 = df1.sort_values(score_col1, ascending=False)
268
+ genes1 = df1[gene_col1].astype(str).tolist()
269
+
270
+ # remove duplicates while preserving order
271
+ genes1 = list(dict.fromkeys(genes1))
272
+
273
+ gene_col2 = df1.columns[0]
274
+ score_col2 = df2.columns[1]
275
+ df2 = df2.sort_values(score_col2, ascending=False)
276
+ genes2 = df2[gene_col2].astype(str).tolist()
277
+ # remove duplicates while preserving order
278
+ genes2 = list(dict.fromkeys(genes2))
279
+
280
+ window = win
281
+ if (len(genes1) < window*3 or len(genes2) < window*3):
282
+ return 0.0, 1.0, 0.0
283
+ rrho_df = rrho_matrix_str(genes1, genes2, window=window)
284
+ plot_rrho(rrho_df)
285
+
286
+ def plot_3D_surface(heatmap_a, out_file=None):
287
+ row_n, col_n = heatmap_a.shape
288
+ x = np.linspace(-1, 1, col_n)
289
+ y = np.linspace(-1, 1, row_n)
290
+ X, Y = np.meshgrid(x, y)
291
+ Z_data = heatmap_a
292
+
293
+ def fit_surface(Z, X, Y):
294
+ df = pd.DataFrame({
295
+ 'x': X.ravel(),
296
+ 'y': Y.ravel(),
297
+ 'z': Z.ravel()
298
+ })
299
+ df['xy'] = df['x'] * df['y'] # 交互项
300
+ X_design = sm.add_constant(df[['x', 'y', 'xy']])
301
+ y_dep = df['z']
302
+ model = sm.OLS(y_dep, X_design).fit()
303
+ beta = model.params
304
+ # print(beta)
305
+
306
+ Z_fit = beta['const'] + beta['x']*X + beta['y']*Y + beta['xy']*X*Y
307
+ return beta, Z_fit
308
+
309
+ beta, Z_fit = fit_surface(Z_data.T, X, Y)
310
+
311
+ fig = plt.figure(figsize=(6, 4), dpi=150)
312
+ ax = fig.add_subplot(111, projection='3d')
313
+
314
+ color = '#e94560' #['#e94560', '#0f3460', '#0f3460']
315
+
316
+ ax.plot_surface(X, Y, Z_fit, cmap='plasma', alpha=0.8)
317
+
318
+ ax.tick_params(axis='x', pad=-5) # x轴标签向外偏移5个点
319
+ ax.tick_params(axis='y', pad=-5) # y轴标签向外偏移5个点
320
+ ax.tick_params(axis='z', pad=0) # z轴标签向外偏移5个点
321
+ ax.set_xlabel('x (Rank A)', fontsize=12, labelpad=-5)
322
+ ax.set_ylabel('y (Rank B)', fontsize=12, labelpad=-5)
323
+ ax.set_zlabel('z (Overlaps)', fontsize=12, labelpad=0)
324
+
325
+ #title = '$z=\\beta_0+\\beta_1x+\\beta_2y+\\beta_3(xy)+\\epsilon$'
326
+ #ax.set_title(title, fontsize=5, fontweight='bold', color='#16213e', pad=1)
327
+ idx = 0
328
+ ax.view_init(elev=20, azim=-55 + idx*12)
329
+
330
+ #beta_text = f'$\\beta_0$={beta['const']:.2f}\n$\\beta_1$={beta['x']:.2f}\n$\\beta_2$={beta['y']:.2f}\n$\\beta_3$={beta['xy']:.2f}'
331
+ #ax.text2D(-0.13, 0.98, beta_text, transform=ax.transAxes, fontsize=4,
332
+ # verticalalignment='top', bbox=dict(boxstyle='round', facecolor='white', alpha=0.8, edgecolor=color, linewidth=0.4))
333
+
334
+ #ax.set_xlim(-1, 1)
335
+ #ax.set_ylim(-1, 1)
336
+ #ax.set_zlim(-3, 8)
337
+ #ax.tick_params(labelsize=3, pad=0)
338
+ # 反转 x 轴
339
+ #ax.invert_yaxis()
340
+ ax.view_init(elev=20, azim=-145)
341
+ plt.tight_layout()
342
+
343
+ if out_file:
344
+ plt.savefig(out_file + '.pdf', dpi=300, bbox_inches="tight")
345
+ plt.savefig(out_file + '.svg', dpi=300, bbox_inches="tight")
346
+ plt.show()
347
+
348
+ def plot_fit3D_plot(df1, df2, win):
349
+ gene_col1 = df1.columns[0]
350
+ score_col1 = df1.columns[1]
351
+ df1 = df1.sort_values(score_col1, ascending=False)
352
+ genes1 = df1[gene_col1].astype(str).tolist()
353
+
354
+ # remove duplicates while preserving order
355
+ genes1 = list(dict.fromkeys(genes1))
356
+
357
+ gene_col2 = df1.columns[0]
358
+ score_col2 = df2.columns[1]
359
+ df2 = df2.sort_values(score_col2, ascending=False)
360
+ genes2 = df2[gene_col2].astype(str).tolist()
361
+ # remove duplicates while preserving order
362
+ genes2 = list(dict.fromkeys(genes2))
363
+
364
+ window = win
365
+ if (len(genes1) < window*3 or len(genes2) < window*3):
366
+ return 0.0, 1.0, 0.0
367
+ rrho_df = rrho_matrix_str(genes1, genes2, window=window)
368
+
369
+ if rrho_df.shape[0] == 0 or rrho_df.shape[1] == 0 or (rrho_df > 0.0).sum().sum() == 0:
370
+ print('no overlaps found')
371
+ exit(1)
372
+
373
+ #beta_xy, pval_xy = td_coor(rrho_df.to_numpy())
374
+ # df = Z_to_frame(rrho_df.to_numpy())
375
+ plot_3D_surface(rrho_df.to_numpy())
376
+
377
+ def rrho_coor_bs(df1, df2, win):
378
+ gene_col1 = df1.columns[0]
379
+ score_col1 = df1.columns[1]
380
+ df1 = df1.sort_values(score_col1, ascending=False)
381
+ genes1 = df1[gene_col1].astype(str).tolist()
382
+
383
+ # remove duplicates while preserving order
384
+ genes1 = list(dict.fromkeys(genes1))
385
+
386
+ gene_col2 = df1.columns[0]
387
+ score_col2 = df2.columns[1]
388
+ df2 = df2.sort_values(score_col2, ascending=False)
389
+ genes2 = df2[gene_col2].astype(str).tolist()
390
+ # remove duplicates while preserving order
391
+ genes2 = list(dict.fromkeys(genes2))
392
+
393
+ window = win
394
+ if (len(genes1) < window*3 or len(genes2) < window*3):
395
+ return 0.0, 1.0, 0.0, 1.0
396
+ rrho_df = rrho_matrix_str(genes1, genes2, window=window)
397
+
398
+ if rrho_df.shape[0] == 0 or rrho_df.shape[1] == 0 or (rrho_df > 0.0).sum().sum() == 0:
399
+ return 0.0, 1.0, 0.0, 1.0
400
+
401
+ #beta_xy, pval_xy = td_coor(rrho_df.to_numpy())
402
+ df = Z_to_frame(rrho_df.to_numpy())
403
+ dtci_res = bootstrap_parametric_h0(df)
404
+ beta_xy = dtci_res['beta3']
405
+ pval_xy = dtci_res['dtci_pval']
406
+ DTCI = dtci_res['dtci_obs']
407
+ bs_pval = dtci_res['p_value']
408
+
409
+ return beta_xy, pval_xy, DTCI, bs_pval
410
+
411
+ def thread_one(tfbs_array, deg_list, win, shared_list, nn, lock):
412
+ tf_n = len(tfbs_array)
413
+ epsilon = 1e-15 # 常用值
414
+ for i in range(tf_n):
415
+ # fin_n += 1
416
+ beta_xy, pval_xy, DTCI = rrho_coor(deg_list, tfbs_array[i][1], win)
417
+ #score = math.pow(abs(beta_xy), 1.0) * math.log10(pval_xy + epsilon) * -1.0
418
+ #if math.isnan(score):
419
+ # score = 0
420
+ with lock:
421
+ shared_list.append([tfbs_array[i][0], beta_xy, pval_xy, DTCI])
422
+ nn[1] += 1
423
+ print(str(nn[1]) + ' / ' + str(nn[0]))
424
+
425
+ def thread_one_bs(tfbs_array, deg_list, win, shared_list, nn, lock):
426
+ tf_n = len(tfbs_array)
427
+ epsilon = 1e-15 # 常用值
428
+ for i in range(tf_n):
429
+ # fin_n += 1
430
+ beta_xy, pval_xy, DTCI, bs_pval = rrho_coor_bs(deg_list, tfbs_array[i][1], win)
431
+ #score = math.pow(abs(beta_xy), 1.0) * math.log10(pval_xy + epsilon) * -1.0
432
+ #if math.isnan(score):
433
+ # score = 0
434
+ with lock:
435
+ shared_list.append([tfbs_array[i][0], beta_xy, pval_xy, DTCI, bs_pval])
436
+ nn[1] += 1
437
+ print(str(nn[1]) + ' / ' + str(nn[0]))
438
+
439
+ def split_into_n_even(lst, n):
440
+ nn = len(lst)
441
+ base = nn // n # 每份基础大小
442
+ remainder = nn % n # 余数,前remainder份各多1个
443
+
444
+ result = []
445
+ start = 0
446
+ for i in range(n):
447
+ size = base + (1 if i < remainder else 0)
448
+ result.append(lst[start:start+size])
449
+ start += size
450
+ return result
451
+
452
+ def olcr(set_names=None, list_file=None, win=30, thread_n=16, data_dir=None):
453
+ if data_dir == None:
454
+ data_dir = overcast_data_dir
455
+ if not (os.path.exists(data_dir) and os.path.isdir(data_dir)):
456
+ print("OVERCAST_data folder can not found!")
457
+ exit(1)
458
+ sets_files = []
459
+ for set1 in set_names:
460
+ sets_file = data_dir + '/TF-target_sets/' + set1 + '.txt'
461
+ if not os.path.exists(sets_file):
462
+ print(sets_file, 'not exist!')
463
+ exit(1)
464
+ else:
465
+ sets_files.append(sets_file)
466
+ degl_file = list_file
467
+ if not os.path.exists(degl_file):
468
+ print(degl_file, 'not exist!')
469
+ exit(1)
470
+
471
+ tfbs_array = read_gene_sets(sets_files)
472
+ deg_list = read_DEG_list(degl_file)
473
+
474
+ manager = mp.Manager()
475
+ shared_list = manager.list([]) # 支持任意类型
476
+ nn = manager.list([len(tfbs_array), 0]) # 支持任意类型
477
+ lock = manager.Lock()
478
+
479
+ tfbs_array_splits = split_into_n_even(tfbs_array, thread_n)
480
+ task_args = []
481
+ for ti in range(thread_n):
482
+ task_args.append((tfbs_array_splits[ti], deg_list, win, shared_list, nn, lock))
483
+
484
+ # 创建进程池
485
+ with mp.Pool(processes=thread_n) as pool:
486
+ print(f"thrend_n:", thread_n)
487
+ print(f"total {len(task_args)} tasks")
488
+ # starmap 会自动分配任务到进程池
489
+ start_time = time.time()
490
+ results = pool.starmap(thread_one, task_args)
491
+ elapsed = time.time() - start_time
492
+ # 打印结果
493
+ print("time consumed:", elapsed)
494
+
495
+ sorted_results = sorted(shared_list, key=itemgetter(-1), reverse=True)
496
+ results = []
497
+ ln = len(sorted_results)
498
+ for li in range(len(sorted_results)):
499
+ ratio = (li + 1) / ln
500
+ rline = sorted_results[li] + [li + 1, ratio]
501
+ results.append(rline)
502
+ col_names = ['TF_motif', 'Beta3', 'Beta3_Pvalue', 'DTCI', 'Rank', 'Rank / N']
503
+ df = pd.DataFrame(results, columns=col_names)
504
+
505
+ return df
506
+
507
+ def olcr_bootstrap(set_names=None, list_file=None, win=30, thread_n=16, data_dir=None):
508
+ if data_dir == None:
509
+ data_dir = overcast_data_dir
510
+ if not (os.path.exists(data_dir) and os.path.isdir(data_dir)):
511
+ print("OVERCAST_data folder can not found!")
512
+ exit(1)
513
+ sets_files = []
514
+ for set1 in set_names:
515
+ sets_file = data_dir + '/TF-target_sets/' + set1 + '.txt'
516
+ if not os.path.exists(sets_file):
517
+ print(sets_file, 'not exist!')
518
+ exit(1)
519
+ else:
520
+ sets_files.append(sets_file)
521
+ degl_file = list_file
522
+ if not os.path.exists(degl_file):
523
+ print(degl_file, 'not exist!')
524
+ exit(1)
525
+
526
+ tfbs_array = read_gene_sets(sets_files)
527
+ deg_list = read_DEG_list(degl_file)
528
+
529
+ manager = mp.Manager()
530
+ shared_list = manager.list([]) # 支持任意类型
531
+ nn = manager.list([len(tfbs_array), 0]) # 支持任意类型
532
+ lock = manager.Lock()
533
+
534
+ tfbs_array_splits = split_into_n_even(tfbs_array, thread_n)
535
+ task_args = []
536
+ for ti in range(thread_n):
537
+ task_args.append((tfbs_array_splits[ti], deg_list, win, shared_list, nn, lock))
538
+
539
+ # 创建进程池
540
+ with mp.Pool(processes=thread_n) as pool:
541
+ print(f"thrend_n:", thread_n)
542
+ print(f"total {len(task_args)} tasks")
543
+ # starmap 会自动分配任务到进程池
544
+ start_time = time.time()
545
+ results = pool.starmap(thread_one_bs, task_args)
546
+ elapsed = time.time() - start_time
547
+ # 打印结果
548
+ print("time consumed:", elapsed)
549
+
550
+ sorted_results = sorted(shared_list, key=lambda x: (x[-1], -x[-2]), reverse=False) # lambda x: (x[4], -x[1]), reverse=False
551
+ results = []
552
+ ln = len(sorted_results)
553
+ for li in range(len(sorted_results)):
554
+ ratio = (li + 1) / ln
555
+ rline = sorted_results[li] + [li + 1, ratio]
556
+ results.append(rline)
557
+ col_names = ['TF_motif', 'Beta3', 'Beta3_Pvalue', 'DTCI', 'DTCI_Pvalue', 'Rank', 'Rank / N']
558
+ df = pd.DataFrame(results, columns=col_names)
559
+
560
+ return df
561
+
562
+ def plot_olc(set_names=['human_hocomoco_CLink_wtcoor_1w_0.8'], list_file='input_deg-list.txt', tf='NFKB1_HUMAN.H11MO.1.B', win=30, data_dir=None):
563
+ if data_dir == None:
564
+ data_dir = overcast_data_dir
565
+ if not (os.path.exists(data_dir) and os.path.isdir(data_dir)):
566
+ print("OVERCAST_data folder can not found!")
567
+ exit(1)
568
+ sets_files = []
569
+ for set1 in set_names:
570
+ sets_file = data_dir + '/TF-target_sets/' + set1 + '.txt'
571
+ if not os.path.exists(sets_file):
572
+ print(sets_file, 'not exist!')
573
+ exit(1)
574
+ else:
575
+ sets_files.append(sets_file)
576
+ degl_file = list_file
577
+ if not os.path.exists(degl_file):
578
+ print(degl_file, 'not exist!')
579
+ exit(1)
580
+
581
+ tfbs_array = read_gene_sets(sets_files)
582
+ deg_list = read_DEG_list(degl_file)
583
+
584
+ tf_n = len(tfbs_array)
585
+ epsilon = 1e-15 # 常用值
586
+ for i in range(tf_n):
587
+ if tfbs_array[i][0] == tf:
588
+ plot_olc_plot(deg_list, tfbs_array[i][1], win)
589
+ break
590
+
591
+ def plot_fit3D(set_names=['human_hocomoco_CLink_wtcoor_1w_0.8'], list_file='input_deg-list.txt', tf='NFKB1_HUMAN.H11MO.1.B', win=30, data_dir=None):
592
+ if data_dir == None:
593
+ data_dir = overcast_data_dir
594
+ if not (os.path.exists(data_dir) and os.path.isdir(data_dir)):
595
+ print("OVERCAST_data folder can not found!")
596
+ exit(1)
597
+ sets_files = []
598
+ for set1 in set_names:
599
+ sets_file = data_dir + '/TF-target_sets/' + set1 + '.txt'
600
+ if not os.path.exists(sets_file):
601
+ print(sets_file, 'not exist!')
602
+ exit(1)
603
+ else:
604
+ sets_files.append(sets_file)
605
+ degl_file = list_file
606
+ if not os.path.exists(degl_file):
607
+ print(degl_file, 'not exist!')
608
+ exit(1)
609
+
610
+ tfbs_array = read_gene_sets(sets_files)
611
+ deg_list = read_DEG_list(degl_file)
612
+
613
+ tf_n = len(tfbs_array)
614
+ epsilon = 1e-15 # 常用值
615
+ for i in range(tf_n):
616
+ if tfbs_array[i][0] == tf:
617
+ plot_fit3D_plot(deg_list, tfbs_array[i][1], win)
618
+ break
619
+
620
+ if __name__ == '__main__':
621
+ '''
622
+ result = olcr(set_names=['human_hocomoco_CLink_wtcoor_1w_0.8', 'human_jaspar_CLink_wtcoor_1w_0.8'], list_file='OVERCAST_data/input_deg-list.txt', win=30, thread_n=16)
623
+ result.to_csv('output.txt', sep='\t', index=False, encoding='utf-8')
624
+
625
+ result = olcr_bootstrap(set_names=['human_hocomoco_CLink_wtcoor_1w_0.8', 'human_jaspar_CLink_wtcoor_1w_0.8'], list_file='OVERCAST_data/input_deg-list.txt', win=30, thread_n=16)
626
+ result.to_csv('output_bootstrap.txt', sep='\t', index=False, encoding='utf-8')
627
+ '''
628
+
629
+ #plot_olc(set_names=['human_hocomoco_CLink_wtcoor_1w_0.8', 'human_jaspar_CLink_wtcoor_1w_0.8'], list_file='OVERCAST_data/input_deg-list.txt', tf='MA0844.2_XBP1', win=30)
630
+
631
+ #plot_fit3D(set_names=['human_hocomoco_CLink_wtcoor_1w_0.8', 'human_jaspar_CLink_wtcoor_1w_0.8'], list_file='OVERCAST_data/input_deg-list.txt', tf='MA0844.2_XBP1', win=30)
@@ -0,0 +1,86 @@
1
+ Metadata-Version: 2.4
2
+ Name: PyOVERCAST
3
+ Version: 1.0.0
4
+ Summary: A Python package for mining key transcription factors from transcriptome data.
5
+ Author-email: Tinghua Huang <thua45@126.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/thua45/PyOVERCAST
8
+ Project-URL: Documentation, https://github.com/thua45/PyOVERCAST#readme
9
+ Project-URL: Repository, https://github.com/thua45/PyOVERCAST
10
+ Project-URL: Issues, https://github.com/thua45/PyOVERCAST/issues
11
+ Keywords: PyOVERCAST,Transcription Factor,Binding Site,Transcriptome Data
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Requires-Python: >=3.11
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: numpy==1.26; sys_platform == "darwin"
21
+ Requires-Dist: numpy>=2.0; sys_platform == "win32"
22
+ Requires-Dist: numpy>=2.0; sys_platform == "linux"
23
+ Requires-Dist: pandas==3.0; sys_platform == "darwin"
24
+ Requires-Dist: pandas>=3.0; sys_platform == "win32"
25
+ Requires-Dist: pandas>=3.0; sys_platform == "linux"
26
+ Requires-Dist: statsmodels==0.14; sys_platform == "darwin"
27
+ Requires-Dist: statsmodels>=0.14; sys_platform == "win32"
28
+ Requires-Dist: statsmodels>=0.14; sys_platform == "linux"
29
+ Requires-Dist: seaborn==0.13; sys_platform == "darwin"
30
+ Requires-Dist: seaborn>=0.13; sys_platform == "win32"
31
+ Requires-Dist: seaborn>=0.13; sys_platform == "linux"
32
+ Requires-Dist: matplotlib==3.11; sys_platform == "darwin"
33
+ Requires-Dist: matplotlib>=3.11; sys_platform == "win32"
34
+ Requires-Dist: matplotlib>=3.11; sys_platform == "linux"
35
+ Provides-Extra: dev
36
+ Requires-Dist: matplotlib; extra == "dev"
37
+ Provides-Extra: test
38
+ Requires-Dist: matplotlib; extra == "test"
39
+ Dynamic: license-file
40
+
41
+ # PyOVERCAST
42
+
43
+ A Python package for mining key transcription factors from transcriptome data.
44
+
45
+ ## Installation
46
+
47
+ ```bash
48
+ pip install numpy pandas statsmodels seaborn matplotlib PyOVERCAST
49
+ ```
50
+
51
+ ## Usage
52
+
53
+ ```python
54
+ from PyOVERCAST import clinks, predict
55
+
56
+ if __name__ == '__main__':
57
+ # download TF-target set, only need to run once!!!
58
+ clinks.download_data()
59
+
60
+ # list available TF-target set
61
+ sets_names = clinks.get_sets(species='Homo sapiens')
62
+ print(sets_names)
63
+
64
+ # list avaiable TFs
65
+ tfs_codes = clinks.get_tfs(set_name='human_hocomoco_CLink_wtcoor_1w_0.8')
66
+ print(tfs_codes)
67
+
68
+ # get targets
69
+ targets = clinks.get_targets(set_name='human_hocomoco_CLink_wtcoor_1w_0.8', tf='NFKB1_HUMAN.H11MO.1.B')
70
+ print(targets)
71
+
72
+ # predict one DEG-list
73
+ result = predict.olcr(set_names=['human_hocomoco_CLink_wtcoor_1w_0.8', 'human_jaspar_CLink_wtcoor_1w_0.8'], list_file='./PyOVERCAST_data/input_deg-list.txt', win=30, thread_n=16)
74
+
75
+ # or predict one DEG-list with bootstrap
76
+ result = predict.olcr_bootstrap(set_names=['human_hocomoco_CLink_wtcoor_1w_0.8', 'human_jaspar_CLink_wtcoor_1w_0.8'], list_file='./PyOVERCAST_data/input_deg-list.txt', win=30, thread_n=16)
77
+
78
+ # save result to text file
79
+ result.to_csv('output.txt', sep='\t', index=False, encoding='utf-8-sig')
80
+
81
+ # plot OLC matrix
82
+ predict.plot_olc(set_names=['human_hocomoco_CLink_wtcoor_1w_0.8', 'human_jaspar_CLink_wtcoor_1w_0.8'], list_file='./PyOVERCAST_data/input_deg-list.txt', tf='MA0844.2_XBP1', win=30)
83
+
84
+ # plot fitted 3D U-surface
85
+ predict.plot_fit3D(set_names=['human_hocomoco_CLink_wtcoor_1w_0.8', 'human_jaspar_CLink_wtcoor_1w_0.8'], list_file='./PyOVERCAST_data/input_deg-list.txt', tf='MA0844.2_XBP1', win=30)
86
+ ```
@@ -0,0 +1,12 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ PyOVERCAST/__init__.py
5
+ PyOVERCAST/clinks.py
6
+ PyOVERCAST/predict.py
7
+ PyOVERCAST.egg-info/PKG-INFO
8
+ PyOVERCAST.egg-info/SOURCES.txt
9
+ PyOVERCAST.egg-info/dependency_links.txt
10
+ PyOVERCAST.egg-info/entry_points.txt
11
+ PyOVERCAST.egg-info/requires.txt
12
+ PyOVERCAST.egg-info/top_level.txt
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ PyOVERCAST = PyOVERCAST.cli:main
3
+ PyOVERCAST-cleanup = PyOVERCAST.uninstall:cleanup
@@ -0,0 +1,27 @@
1
+
2
+ [:sys_platform == "darwin"]
3
+ numpy==1.26
4
+ pandas==3.0
5
+ statsmodels==0.14
6
+ seaborn==0.13
7
+ matplotlib==3.11
8
+
9
+ [:sys_platform == "linux"]
10
+ numpy>=2.0
11
+ pandas>=3.0
12
+ statsmodels>=0.14
13
+ seaborn>=0.13
14
+ matplotlib>=3.11
15
+
16
+ [:sys_platform == "win32"]
17
+ numpy>=2.0
18
+ pandas>=3.0
19
+ statsmodels>=0.14
20
+ seaborn>=0.13
21
+ matplotlib>=3.11
22
+
23
+ [dev]
24
+ matplotlib
25
+
26
+ [test]
27
+ matplotlib
@@ -0,0 +1 @@
1
+ PyOVERCAST
@@ -0,0 +1,46 @@
1
+ # PyOVERCAST
2
+
3
+ A Python package for mining key transcription factors from transcriptome data.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install numpy pandas statsmodels seaborn matplotlib PyOVERCAST
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```python
14
+ from PyOVERCAST import clinks, predict
15
+
16
+ if __name__ == '__main__':
17
+ # download TF-target set, only need to run once!!!
18
+ clinks.download_data()
19
+
20
+ # list available TF-target set
21
+ sets_names = clinks.get_sets(species='Homo sapiens')
22
+ print(sets_names)
23
+
24
+ # list avaiable TFs
25
+ tfs_codes = clinks.get_tfs(set_name='human_hocomoco_CLink_wtcoor_1w_0.8')
26
+ print(tfs_codes)
27
+
28
+ # get targets
29
+ targets = clinks.get_targets(set_name='human_hocomoco_CLink_wtcoor_1w_0.8', tf='NFKB1_HUMAN.H11MO.1.B')
30
+ print(targets)
31
+
32
+ # predict one DEG-list
33
+ result = predict.olcr(set_names=['human_hocomoco_CLink_wtcoor_1w_0.8', 'human_jaspar_CLink_wtcoor_1w_0.8'], list_file='./PyOVERCAST_data/input_deg-list.txt', win=30, thread_n=16)
34
+
35
+ # or predict one DEG-list with bootstrap
36
+ result = predict.olcr_bootstrap(set_names=['human_hocomoco_CLink_wtcoor_1w_0.8', 'human_jaspar_CLink_wtcoor_1w_0.8'], list_file='./PyOVERCAST_data/input_deg-list.txt', win=30, thread_n=16)
37
+
38
+ # save result to text file
39
+ result.to_csv('output.txt', sep='\t', index=False, encoding='utf-8-sig')
40
+
41
+ # plot OLC matrix
42
+ predict.plot_olc(set_names=['human_hocomoco_CLink_wtcoor_1w_0.8', 'human_jaspar_CLink_wtcoor_1w_0.8'], list_file='./PyOVERCAST_data/input_deg-list.txt', tf='MA0844.2_XBP1', win=30)
43
+
44
+ # plot fitted 3D U-surface
45
+ predict.plot_fit3D(set_names=['human_hocomoco_CLink_wtcoor_1w_0.8', 'human_jaspar_CLink_wtcoor_1w_0.8'], list_file='./PyOVERCAST_data/input_deg-list.txt', tf='MA0844.2_XBP1', win=30)
46
+ ```
@@ -0,0 +1,62 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "PyOVERCAST"
7
+ version = "1.0.0"
8
+ license = "MIT" # SPDX expression
9
+ description = "A Python package for mining key transcription factors from transcriptome data."
10
+ readme = "README.md"
11
+ requires-python = ">=3.11"
12
+ authors = [
13
+ {name = "Tinghua Huang", email = "thua45@126.com"}
14
+ ]
15
+ keywords = ["PyOVERCAST", "Transcription Factor", "Binding Site", 'Transcriptome Data']
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Developers",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Programming Language :: Python :: 3.13",
22
+ ]
23
+ dependencies = [
24
+ "numpy==1.26; sys_platform == 'darwin'",
25
+ "numpy>=2.0; sys_platform == 'win32'",
26
+ "numpy>=2.0; sys_platform == 'linux'",
27
+ "pandas==3.0; sys_platform == 'darwin'",
28
+ "pandas>=3.0; sys_platform == 'win32'",
29
+ "pandas>=3.0; sys_platform == 'linux'",
30
+ "statsmodels==0.14; sys_platform == 'darwin'",
31
+ "statsmodels>=0.14; sys_platform == 'win32'",
32
+ "statsmodels>=0.14; sys_platform == 'linux'",
33
+ "seaborn==0.13; sys_platform == 'darwin'",
34
+ "seaborn>=0.13; sys_platform == 'win32'",
35
+ "seaborn>=0.13; sys_platform == 'linux'",
36
+ "matplotlib==3.11; sys_platform == 'darwin'",
37
+ "matplotlib>=3.11; sys_platform == 'win32'",
38
+ "matplotlib>=3.11; sys_platform == 'linux'",
39
+ ]
40
+
41
+ [project.urls]
42
+ Homepage = "https://github.com/thua45/PyOVERCAST"
43
+ Documentation = "https://github.com/thua45/PyOVERCAST#readme"
44
+ Repository = "https://github.com/thua45/PyOVERCAST"
45
+ Issues = "https://github.com/thua45/PyOVERCAST/issues"
46
+
47
+ [project.optional-dependencies]
48
+ dev = [
49
+ "matplotlib",
50
+ ]
51
+ test = [
52
+ "matplotlib",
53
+ ]
54
+
55
+ [project.scripts]
56
+ PyOVERCAST = "PyOVERCAST.cli:main"
57
+ PyOVERCAST-cleanup = "PyOVERCAST.uninstall:cleanup"
58
+
59
+ [tool.setuptools]
60
+ packages = ["PyOVERCAST"]
61
+ package-data = {"*" = ["*.txt", "*.md", "*.rst", "data/*"]}
62
+
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+