ScreenPro2 0.5.0__py3-none-any.whl
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.
- pyproject.toml +30 -0
- screenpro/__init__.py +31 -0
- screenpro/__main__.py +8 -0
- screenpro/assays/__init__.py +465 -0
- screenpro/dashboard/__init__.py +293 -0
- screenpro/load.py +239 -0
- screenpro/main.py +227 -0
- screenpro/ngs/__init__.py +390 -0
- screenpro/ngs/cas12.py +206 -0
- screenpro/ngs/cas9.py +276 -0
- screenpro/phenoscore/__init__.py +148 -0
- screenpro/phenoscore/_annotate.py +122 -0
- screenpro/phenoscore/delta.py +375 -0
- screenpro/phenoscore/deseq.py +57 -0
- screenpro/phenoscore/evaluate.py +66 -0
- screenpro/phenoscore/phenostat.py +84 -0
- screenpro/plotting/__init__.py +9 -0
- screenpro/plotting/_rank.py +88 -0
- screenpro/plotting/_utils.py +81 -0
- screenpro/plotting/pheno_plots.py +196 -0
- screenpro/plotting/qc_plots.py +45 -0
- screenpro/preprocessing.py +98 -0
- screenpro2-0.5.0.dist-info/LICENSE +25 -0
- screenpro2-0.5.0.dist-info/METADATA +366 -0
- screenpro2-0.5.0.dist-info/RECORD +27 -0
- screenpro2-0.5.0.dist-info/WHEEL +4 -0
- screenpro2-0.5.0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
## Copyright (c) 2022-2025 ScreenPro2 Development Team.
|
|
2
|
+
## All rights reserved.
|
|
3
|
+
## Gilbart Lab, UCSF / Arc Institute.
|
|
4
|
+
## Multi-Omics Tech Center, Arc Insititue.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pandas as pd
|
|
9
|
+
import bokeh
|
|
10
|
+
import bokeh.plotting
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DataDashboard:
|
|
14
|
+
|
|
15
|
+
def __init__(self):
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
def _new_plot(self,title,tooltips,width,height,toolbar_location):
|
|
19
|
+
|
|
20
|
+
TOOLS = "box_select,box_zoom,lasso_select,reset,save,wheel_zoom,pan,copy,undo,redo,reset,examine,fullscreen"
|
|
21
|
+
|
|
22
|
+
# create a new plot with a specific size
|
|
23
|
+
p = bokeh.plotting.figure(
|
|
24
|
+
sizing_mode="stretch_width",
|
|
25
|
+
tools=TOOLS,
|
|
26
|
+
tooltips=tooltips,
|
|
27
|
+
toolbar_location=toolbar_location,
|
|
28
|
+
title=title,
|
|
29
|
+
max_width=width, height=height,
|
|
30
|
+
)
|
|
31
|
+
p.toolbar.autohide = True
|
|
32
|
+
return p
|
|
33
|
+
|
|
34
|
+
def _get_html(self, p):
|
|
35
|
+
html = bokeh.embed.file_html(p, bokeh.resources.CDN, "")
|
|
36
|
+
return html
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class DrugScreenDashboard(DataDashboard):
|
|
40
|
+
|
|
41
|
+
def __init__(
|
|
42
|
+
self, screen, treated, untreated,
|
|
43
|
+
t0='T0', threshold=3, ctrl_label='negative_control',
|
|
44
|
+
run_name='auto',
|
|
45
|
+
score_col='score', pvalue_col='pvalue'
|
|
46
|
+
):
|
|
47
|
+
self.screen = screen
|
|
48
|
+
self.threshold = threshold
|
|
49
|
+
self.ctrl_label = ctrl_label
|
|
50
|
+
self.run_name = run_name
|
|
51
|
+
self.gamma_score_name = f'gamma:{untreated}_vs_{t0}'
|
|
52
|
+
self.rho_score_name = f'rho:{treated}_vs_{untreated}'
|
|
53
|
+
self.df = self._prep_data(screen, score_col=score_col, pvalue_col=pvalue_col)
|
|
54
|
+
self.plots = {}
|
|
55
|
+
super().__init__()
|
|
56
|
+
|
|
57
|
+
def _prep_data(self,screen, score_col='score', pvalue_col='pvalue'):
|
|
58
|
+
|
|
59
|
+
gamma = screen.getPhenotypeScores(
|
|
60
|
+
phenotype_name=self.gamma_score_name,
|
|
61
|
+
run_name=self.run_name,
|
|
62
|
+
threshold=self.threshold,
|
|
63
|
+
ctrl_label=self.ctrl_label,
|
|
64
|
+
score_col=score_col,
|
|
65
|
+
pvalue_col=pvalue_col
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
rho = screen.getPhenotypeScores(
|
|
69
|
+
phenotype_name=self.rho_score_name,
|
|
70
|
+
run_name=self.run_name,
|
|
71
|
+
threshold=self.threshold,
|
|
72
|
+
ctrl_label=self.ctrl_label,
|
|
73
|
+
score_col=score_col,
|
|
74
|
+
pvalue_col=pvalue_col
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
df = pd.DataFrame({
|
|
78
|
+
'target': rho['target'],
|
|
79
|
+
'rho_score': rho['score'],
|
|
80
|
+
'rho_pvalue': rho[pvalue_col],
|
|
81
|
+
'rho_label': rho['label'],
|
|
82
|
+
'-log10(rho_pvalue)': np.log10(rho[pvalue_col]) * -1,
|
|
83
|
+
'gamma_score': gamma.loc[rho.index,'score'],
|
|
84
|
+
'gamma_pvalue': gamma.loc[rho.index,pvalue_col],
|
|
85
|
+
'gamma_label': gamma.loc[rho.index,'label'],
|
|
86
|
+
'-log10(gamma_pvalue)': np.log10(gamma.loc[rho.index,pvalue_col]) * -1,
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
return df
|
|
90
|
+
|
|
91
|
+
def _plot_scatter(
|
|
92
|
+
self,
|
|
93
|
+
x_source,y_source,
|
|
94
|
+
xaxis_label,yaxis_label,
|
|
95
|
+
up_hit, down_hit,
|
|
96
|
+
hit_label_col,
|
|
97
|
+
x_min, x_max, y_min, y_max,
|
|
98
|
+
title='',
|
|
99
|
+
dot_size=1,
|
|
100
|
+
width=500, height=400,
|
|
101
|
+
toolbar_location='below',
|
|
102
|
+
legend_loc="top_left",
|
|
103
|
+
):
|
|
104
|
+
df = self.df.copy()
|
|
105
|
+
if y_max == 'auto': y_max = df[y_source].max() * 1.2
|
|
106
|
+
if x_max == 'auto': x_max = df[x_source].max() * 1.2
|
|
107
|
+
if y_min == 'auto': y_min = df[y_source].min() * 1.2
|
|
108
|
+
if x_min == 'auto': x_min = df[x_source].min() * 1.2
|
|
109
|
+
|
|
110
|
+
TOOLTIPS = [
|
|
111
|
+
("name", "@target"),
|
|
112
|
+
("rho score", "@rho_score"),
|
|
113
|
+
("rho p-value", "@rho_pvalue"),
|
|
114
|
+
("rho label", "@rho_label"),
|
|
115
|
+
("gamma score", "@gamma_score"),
|
|
116
|
+
("gamma p-value", "@gamma_pvalue"),
|
|
117
|
+
("gamma label", "@gamma_label"),
|
|
118
|
+
]
|
|
119
|
+
|
|
120
|
+
p = self._new_plot(
|
|
121
|
+
title=title,
|
|
122
|
+
tooltips=TOOLTIPS,
|
|
123
|
+
width=width,
|
|
124
|
+
height=height,
|
|
125
|
+
toolbar_location=toolbar_location
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
source = bokeh.models.ColumnDataSource(
|
|
129
|
+
df.loc[df[hit_label_col] == 'target_non_hit',:]
|
|
130
|
+
)
|
|
131
|
+
p.scatter(
|
|
132
|
+
x=x_source, y=y_source,
|
|
133
|
+
source=source,
|
|
134
|
+
alpha=0.2,
|
|
135
|
+
size=dot_size * 1.2,
|
|
136
|
+
color='gray',
|
|
137
|
+
legend_label='target_non_hit',
|
|
138
|
+
name='circles'
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
# size_mapper=bokeh.models.LinearInterpolator(
|
|
142
|
+
# x=[df['1/gamma_score'].min(),df['1/gamma_score'].max()],
|
|
143
|
+
# y=[1,100]
|
|
144
|
+
# )
|
|
145
|
+
|
|
146
|
+
source = bokeh.models.ColumnDataSource(
|
|
147
|
+
df.loc[df[hit_label_col] == up_hit,:]
|
|
148
|
+
)
|
|
149
|
+
p.scatter(
|
|
150
|
+
x=x_source, y=y_source,
|
|
151
|
+
source=source,
|
|
152
|
+
alpha=0.8,
|
|
153
|
+
size=dot_size * 1.2,
|
|
154
|
+
# size={'field':'1/gamma_score','transform':size_mapper},
|
|
155
|
+
color='#fcae91',
|
|
156
|
+
legend_label=up_hit,
|
|
157
|
+
name='circles'
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
source = bokeh.models.ColumnDataSource(
|
|
161
|
+
df.loc[df[hit_label_col] == down_hit,:]
|
|
162
|
+
)
|
|
163
|
+
p.scatter(
|
|
164
|
+
x=x_source, y=y_source,
|
|
165
|
+
source=source,
|
|
166
|
+
alpha=0.8,
|
|
167
|
+
# size={'field':'1/gamma_score','transform':size_mapper},
|
|
168
|
+
size=dot_size * 1.2,
|
|
169
|
+
color='#bdd7e7',
|
|
170
|
+
legend_label=down_hit,
|
|
171
|
+
name='circles'
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
source = bokeh.models.ColumnDataSource(
|
|
175
|
+
df.loc[df[hit_label_col] == self.ctrl_label,:]
|
|
176
|
+
)
|
|
177
|
+
p.scatter(
|
|
178
|
+
x=x_source, y=y_source,
|
|
179
|
+
source=source,
|
|
180
|
+
alpha=0.2,
|
|
181
|
+
size=dot_size*0.8,
|
|
182
|
+
color='silver',
|
|
183
|
+
legend_label=self.ctrl_label,
|
|
184
|
+
name='circles'
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Set x-axis and y-axis labels
|
|
188
|
+
p.xaxis.axis_label = xaxis_label
|
|
189
|
+
p.xaxis.axis_label_text_font_style = 'normal'
|
|
190
|
+
p.yaxis.axis_label = yaxis_label
|
|
191
|
+
p.yaxis.axis_label_text_font_style = 'normal'
|
|
192
|
+
|
|
193
|
+
# Set x-axis limits
|
|
194
|
+
p.x_range.start = x_min
|
|
195
|
+
p.x_range.end = x_max
|
|
196
|
+
|
|
197
|
+
# Set y-axis limits
|
|
198
|
+
p.y_range.start = y_min
|
|
199
|
+
p.y_range.end = y_max
|
|
200
|
+
|
|
201
|
+
# Add legend
|
|
202
|
+
if legend_loc == False or legend_loc == None:
|
|
203
|
+
p.legend.visible = False
|
|
204
|
+
else:
|
|
205
|
+
p.legend.location = legend_loc
|
|
206
|
+
|
|
207
|
+
p.title.text = title
|
|
208
|
+
p.title.align = 'center'
|
|
209
|
+
p.title.text_font_size = '12pt'
|
|
210
|
+
p.title.text_font_style = 'bold'
|
|
211
|
+
|
|
212
|
+
return p
|
|
213
|
+
|
|
214
|
+
def RhoVolcanoPlot(
|
|
215
|
+
self,
|
|
216
|
+
x_source='rho_score', y_source='-log10(rho_pvalue)',
|
|
217
|
+
xaxis_label='phenotype score',
|
|
218
|
+
yaxis_label='-log10(p-value)',
|
|
219
|
+
up_hit='resistance_hit', down_hit='sensitivity_hit',
|
|
220
|
+
hit_label_col='rho_label',
|
|
221
|
+
x_min=-2.5, x_max=2.5, y_min=0, y_max='auto',
|
|
222
|
+
return_html=True,
|
|
223
|
+
**kwargs
|
|
224
|
+
):
|
|
225
|
+
p = self._plot_scatter(
|
|
226
|
+
x_source, y_source,
|
|
227
|
+
xaxis_label, yaxis_label,
|
|
228
|
+
up_hit, down_hit,
|
|
229
|
+
hit_label_col,
|
|
230
|
+
x_min, x_max, y_min, y_max,
|
|
231
|
+
**kwargs
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
if return_html:
|
|
235
|
+
return self._get_html(p)
|
|
236
|
+
|
|
237
|
+
self.plots.update(
|
|
238
|
+
{'RhoVolcanoPlot': p}
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
def GammaVolcanoPlot(
|
|
242
|
+
self,
|
|
243
|
+
x_source='gamma_score', y_source='-log10(gamma_pvalue)',
|
|
244
|
+
xaxis_label='phenotype score',
|
|
245
|
+
yaxis_label='-log10(p-value)',
|
|
246
|
+
up_hit='up_hit', down_hit='essential_hit',
|
|
247
|
+
hit_label_col='gamma_label',
|
|
248
|
+
x_min=-2.5, x_max=2.5, y_min=0, y_max='auto',
|
|
249
|
+
return_html=True,
|
|
250
|
+
**kwargs
|
|
251
|
+
):
|
|
252
|
+
p = self._plot_scatter(
|
|
253
|
+
x_source, y_source,
|
|
254
|
+
xaxis_label, yaxis_label,
|
|
255
|
+
up_hit, down_hit,
|
|
256
|
+
hit_label_col,
|
|
257
|
+
x_min, x_max, y_min, y_max,
|
|
258
|
+
**kwargs
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
if return_html:
|
|
262
|
+
return self._get_html(p)
|
|
263
|
+
|
|
264
|
+
self.plots.update(
|
|
265
|
+
{'GammaVolcanoPlot': p}
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
def RhoGammaScatter(
|
|
269
|
+
self,
|
|
270
|
+
x_source='rho_score', y_source='gamma_score',
|
|
271
|
+
xaxis_label='rho score',
|
|
272
|
+
yaxis_label='gamma score',
|
|
273
|
+
up_hit='resistance_hit', down_hit='sensitivity_hit',
|
|
274
|
+
hit_label_col='rho_label',
|
|
275
|
+
x_min=-2.5, x_max=2.5, y_min=-2.5, y_max=2.5,
|
|
276
|
+
return_html=True,
|
|
277
|
+
**kwargs
|
|
278
|
+
):
|
|
279
|
+
p = self._plot_scatter(
|
|
280
|
+
x_source, y_source,
|
|
281
|
+
xaxis_label, yaxis_label,
|
|
282
|
+
up_hit, down_hit,
|
|
283
|
+
hit_label_col,
|
|
284
|
+
x_min, x_max, y_min, y_max,
|
|
285
|
+
**kwargs
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
if return_html:
|
|
289
|
+
return self._get_html(p)
|
|
290
|
+
|
|
291
|
+
self.plots.update(
|
|
292
|
+
{'GammaRhoScatter': p}
|
|
293
|
+
)
|
screenpro/load.py
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
## Copyright (c) 2022-2024 ScreenPro2 Development Team.
|
|
2
|
+
## All rights reserved.
|
|
3
|
+
## Gilbart Lab, UCSF / Arc Institute.
|
|
4
|
+
## Multi-Omics Tech Center, Arc Insititue.
|
|
5
|
+
|
|
6
|
+
"""Load module
|
|
7
|
+
|
|
8
|
+
Functions to load screen datasets and sgRNA library tables.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import pickle
|
|
12
|
+
import pandas as pd
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def load_cas9_sgRNA_library(library_path, library_type, sep='\t', index_col=0, protospacer_length=19, verbose=True, **args):
|
|
16
|
+
'''Load Cas9 sgRNA library table for single or dual guide design.
|
|
17
|
+
'''
|
|
18
|
+
library = pd.read_csv(
|
|
19
|
+
library_path,
|
|
20
|
+
sep=sep,
|
|
21
|
+
index_col=index_col,
|
|
22
|
+
**args
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
## Evaluate library table and reformat columns for downstream analysis
|
|
26
|
+
# I would like to name the target column 'target' if it is named 'gene'!
|
|
27
|
+
#TODO: Add option to keep sublibrary column!
|
|
28
|
+
|
|
29
|
+
if library_type == "single_guide_design":
|
|
30
|
+
eval_columns = ['target', 'sgID', 'protospacer', 'sequence']
|
|
31
|
+
|
|
32
|
+
# reformating columns as needed
|
|
33
|
+
if 'gene' in library.columns:
|
|
34
|
+
# rename gene column to target
|
|
35
|
+
library = library.rename(columns={'gene': 'target'})
|
|
36
|
+
if 'sequence' in library.columns and 'protospacer' not in library.columns:
|
|
37
|
+
library.rename(columns={'sequence': 'protospacer'}, inplace=True)
|
|
38
|
+
if 'sgId' in library.columns:
|
|
39
|
+
library.rename(columns={'sgId': 'sgID'}, inplace=True)
|
|
40
|
+
|
|
41
|
+
# Upper case protospacer sequences
|
|
42
|
+
library['protospacer'] = library['protospacer'].str.upper()
|
|
43
|
+
|
|
44
|
+
protospacer_col = 'protospacer'
|
|
45
|
+
in_length = _check_protospacer_length(library, 'protospacer')
|
|
46
|
+
if in_length == protospacer_length:
|
|
47
|
+
pass
|
|
48
|
+
elif in_length > protospacer_length:
|
|
49
|
+
if verbose: print(f"Trimming protospacer sequences in '{protospacer_col}' column.")
|
|
50
|
+
library = _trim_protospacer(
|
|
51
|
+
library, protospacer_col,
|
|
52
|
+
'5prime',
|
|
53
|
+
in_length - protospacer_length
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
elif in_length < protospacer_length:
|
|
57
|
+
raise ValueError(
|
|
58
|
+
f"Input protospacer length for '{protospacer_col}' is less than {protospacer_length}"
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# write `sequence` column as `protospacer` (after trimming)
|
|
62
|
+
library['sequence'] = library['protospacer']
|
|
63
|
+
|
|
64
|
+
for col in eval_columns:
|
|
65
|
+
if col not in library.columns:
|
|
66
|
+
raise ValueError(f"Column '{col}' not found in library table.")
|
|
67
|
+
|
|
68
|
+
library = library[eval_columns]
|
|
69
|
+
|
|
70
|
+
elif library_type == "dual_guide_design":
|
|
71
|
+
eval_columns = [
|
|
72
|
+
'target', 'sgID_AB',
|
|
73
|
+
'sgID_A', 'protospacer_A',
|
|
74
|
+
'sgID_B', 'protospacer_B',
|
|
75
|
+
'sequence'
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
# reformating columns as needed
|
|
79
|
+
if 'gene' in library.columns:
|
|
80
|
+
# rename gene column to target
|
|
81
|
+
library = library.rename(columns={'gene': 'target'})
|
|
82
|
+
|
|
83
|
+
# Upper case protospacer sequences
|
|
84
|
+
library['protospacer_A'] = library['protospacer_A'].str.upper()
|
|
85
|
+
library['protospacer_B'] = library['protospacer_B'].str.upper()
|
|
86
|
+
|
|
87
|
+
# # TODO: Enable trimming of protospacer sequences through command line arguments.
|
|
88
|
+
for protospacer_col in ['protospacer_A', 'protospacer_B']:
|
|
89
|
+
in_length = _check_protospacer_length(library, protospacer_col)
|
|
90
|
+
if in_length == protospacer_length:
|
|
91
|
+
pass
|
|
92
|
+
elif in_length > protospacer_length:
|
|
93
|
+
if verbose: print(f"Trimming protospacer sequences in '{protospacer_col}' column.")
|
|
94
|
+
library = _trim_protospacer(
|
|
95
|
+
library, protospacer_col,
|
|
96
|
+
'5prime',
|
|
97
|
+
in_length - protospacer_length
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
elif in_length < protospacer_length:
|
|
101
|
+
raise ValueError(
|
|
102
|
+
f"Input protospacer length for '{protospacer_col}' is less than {protospacer_length}"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# write `sequence` column as `protospacer_A;protospacer_B` (after trimming)
|
|
106
|
+
library['sequence'] = library['protospacer_A'] + ';' + library['protospacer_B']
|
|
107
|
+
|
|
108
|
+
for col in eval_columns:
|
|
109
|
+
if col not in library.columns:
|
|
110
|
+
raise ValueError(f"Column '{col}' not found in library table.")
|
|
111
|
+
|
|
112
|
+
library = library[eval_columns]
|
|
113
|
+
|
|
114
|
+
else:
|
|
115
|
+
raise ValueError(f"Invalid library type: {library_type}. Please choose 'single_guide_design' or 'dual_guide_design'.")
|
|
116
|
+
|
|
117
|
+
if verbose: print("Library table successfully loaded.")
|
|
118
|
+
|
|
119
|
+
return library
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def loadScreenProcessingData(experimentName, collapsedToTranscripts=True, premergedCounts=False):
|
|
123
|
+
"""
|
|
124
|
+
Load ScreenProcessing outputs
|
|
125
|
+
(see original code `here <https://github.com/mhorlbeck/ScreenProcessing/blob/master/screen_analysis.py#L70>`__)
|
|
126
|
+
Input files:
|
|
127
|
+
* `*_librarytable.txt` => library table
|
|
128
|
+
* `*_mergedcountstable.txt` => merged counts table
|
|
129
|
+
* `*_phenotypetable.txt` => phenotype table
|
|
130
|
+
|
|
131
|
+
Parameters:
|
|
132
|
+
experimentName (str): name of the experiment
|
|
133
|
+
collapsedToTranscripts (bool): whether the gene scores are collapsed to transcripts
|
|
134
|
+
premergedCounts (bool): whether the counts are premerged
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
dict: dictionary of dataframes
|
|
138
|
+
"""
|
|
139
|
+
# dict of dataframes
|
|
140
|
+
dataDict = {
|
|
141
|
+
'library': pd.read_csv(
|
|
142
|
+
experimentName + '_librarytable.txt',
|
|
143
|
+
sep='\t',
|
|
144
|
+
header=0,
|
|
145
|
+
index_col=0
|
|
146
|
+
),
|
|
147
|
+
'counts': pd.read_csv(
|
|
148
|
+
experimentName + '_mergedcountstable.txt',
|
|
149
|
+
sep='\t',
|
|
150
|
+
header=list(range(2)),
|
|
151
|
+
index_col=list(range(1))
|
|
152
|
+
),
|
|
153
|
+
'phenotypes': pd.read_csv(
|
|
154
|
+
experimentName + '_phenotypetable.txt',
|
|
155
|
+
sep='\t',
|
|
156
|
+
header=list(range(2)),
|
|
157
|
+
index_col=list(range(1))
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if premergedCounts:
|
|
162
|
+
# add premerged counts
|
|
163
|
+
dataDict['premerged counts'] = pd.read_csv(
|
|
164
|
+
experimentName + '_rawcountstable.txt',
|
|
165
|
+
sep='\t',
|
|
166
|
+
header=list(range(3)),
|
|
167
|
+
index_col=list(range(1))
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
if collapsedToTranscripts:
|
|
171
|
+
# add transcript scores
|
|
172
|
+
dataDict['transcript scores'] = pd.read_csv(
|
|
173
|
+
experimentName + '_genetable.txt',
|
|
174
|
+
sep='\t',
|
|
175
|
+
header=list(range(3)),
|
|
176
|
+
index_col=list(range(2))
|
|
177
|
+
)
|
|
178
|
+
dataDict['gene scores'] = pd.read_csv(
|
|
179
|
+
experimentName + '_genetable_collapsed.txt',
|
|
180
|
+
sep='\t',
|
|
181
|
+
header=list(range(3)),
|
|
182
|
+
index_col=list(range(1))
|
|
183
|
+
)
|
|
184
|
+
else:
|
|
185
|
+
# add gene scores
|
|
186
|
+
dataDict['gene scores'] = pd.read_csv(
|
|
187
|
+
experimentName + '_genetable.txt',
|
|
188
|
+
sep='\t',
|
|
189
|
+
header=list(range(3)),
|
|
190
|
+
index_col=list(range(1))
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
return dataDict
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _check_protospacer_length(library, protospacer_col):
|
|
197
|
+
lengths = list(set(library[protospacer_col].str.len()))
|
|
198
|
+
if len(lengths) > 1:
|
|
199
|
+
raise ValueError(f"Protospacer lengths are not uniform: {lengths}")
|
|
200
|
+
else:
|
|
201
|
+
length = lengths[0]
|
|
202
|
+
return length
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def _trim_protospacer(library, protospacer_col, trim_side, trim_len):
|
|
206
|
+
if trim_side == '5prime':
|
|
207
|
+
library[protospacer_col] = library[protospacer_col].str[trim_len:].str.upper()
|
|
208
|
+
|
|
209
|
+
elif trim_side == '3prime':
|
|
210
|
+
library[protospacer_col] = library[protospacer_col].str[:-trim_len].str.upper()
|
|
211
|
+
|
|
212
|
+
return library
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def _write_screen_pkl(screen, name):
|
|
216
|
+
"""
|
|
217
|
+
Write AnnData object to a pickle file
|
|
218
|
+
|
|
219
|
+
Parameters:
|
|
220
|
+
screen (object): ScreenPro object to save
|
|
221
|
+
name (str): name of the output file (.pkl extension will be added)
|
|
222
|
+
"""
|
|
223
|
+
file_name = f'{name}.pkl'
|
|
224
|
+
with open(file_name, 'wb') as file:
|
|
225
|
+
pickle.dump(screen, file)
|
|
226
|
+
print(f'Object successfully saved to "{file_name}"')
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _read_screen_pkl(name):
|
|
230
|
+
"""
|
|
231
|
+
Read ScreenPro object from a pickle file
|
|
232
|
+
|
|
233
|
+
Parameters:
|
|
234
|
+
name (str): name of the input file (.pkl extension will be added)
|
|
235
|
+
"""
|
|
236
|
+
file_name = f'{name}.pkl'
|
|
237
|
+
with open(file_name, 'rb') as f:
|
|
238
|
+
screen = pickle.load(f)
|
|
239
|
+
return screen
|