RNAvigate 1.1.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.
Files changed (57) hide show
  1. rnavigate/__init__.py +63 -0
  2. rnavigate/analysis/__init__.py +18 -0
  3. rnavigate/analysis/auroc.py +198 -0
  4. rnavigate/analysis/check_sequence.py +171 -0
  5. rnavigate/analysis/deltashape.py +361 -0
  6. rnavigate/analysis/fragmapper.py +463 -0
  7. rnavigate/analysis/logcompare.py +239 -0
  8. rnavigate/analysis/lowss.py +311 -0
  9. rnavigate/data/__init__.py +78 -0
  10. rnavigate/data/alignments.py +927 -0
  11. rnavigate/data/annotation.py +456 -0
  12. rnavigate/data/colors.py +154 -0
  13. rnavigate/data/data.py +620 -0
  14. rnavigate/data/interactions.py +1750 -0
  15. rnavigate/data/pdb.py +271 -0
  16. rnavigate/data/profile.py +1080 -0
  17. rnavigate/data/secondary_structure.py +1433 -0
  18. rnavigate/data_loading.py +214 -0
  19. rnavigate/examples/__init__.py +178 -0
  20. rnavigate/examples/rmrp_data/__init__.py +0 -0
  21. rnavigate/examples/rnasep_data/__init__.py +0 -0
  22. rnavigate/examples/rrna_fragmap_data/__init__.py +0 -0
  23. rnavigate/examples/tpp_data/__init__.py +0 -0
  24. rnavigate/helper_functions.py +223 -0
  25. rnavigate/plots/__init__.py +81 -0
  26. rnavigate/plots/alignment.py +115 -0
  27. rnavigate/plots/arc.py +350 -0
  28. rnavigate/plots/circle.py +221 -0
  29. rnavigate/plots/disthist.py +209 -0
  30. rnavigate/plots/functions/__init__.py +55 -0
  31. rnavigate/plots/functions/circle.py +74 -0
  32. rnavigate/plots/functions/functions.py +337 -0
  33. rnavigate/plots/functions/ss.py +312 -0
  34. rnavigate/plots/functions/tracks.py +227 -0
  35. rnavigate/plots/heatmap.py +245 -0
  36. rnavigate/plots/linreg.py +284 -0
  37. rnavigate/plots/mol.py +280 -0
  38. rnavigate/plots/ntdist.py +131 -0
  39. rnavigate/plots/plots.py +348 -0
  40. rnavigate/plots/profile.py +253 -0
  41. rnavigate/plots/qc.py +262 -0
  42. rnavigate/plots/roc.py +181 -0
  43. rnavigate/plots/skyline.py +287 -0
  44. rnavigate/plots/sm.py +416 -0
  45. rnavigate/plots/ss.py +180 -0
  46. rnavigate/plotting_functions.py +1622 -0
  47. rnavigate/rnavigate.py +363 -0
  48. rnavigate/styles.py +247 -0
  49. rnavigate/transcriptomics/__init__.py +20 -0
  50. rnavigate/transcriptomics/bed.py +185 -0
  51. rnavigate/transcriptomics/eclip.py +262 -0
  52. rnavigate/transcriptomics/transcriptome.py +343 -0
  53. rnavigate-1.1.0.dist-info/METADATA +75 -0
  54. rnavigate-1.1.0.dist-info/RECORD +57 -0
  55. rnavigate-1.1.0.dist-info/WHEEL +5 -0
  56. rnavigate-1.1.0.dist-info/licenses/LICENSE +21 -0
  57. rnavigate-1.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,361 @@
1
+ #!/usr/bin/env python
2
+ """DeltaSHAPE for detecting meaningful changes in SHAPE reactivity between two samples.
3
+
4
+ Parameters are optimized for detecting in cell vs. cell free protein protections and
5
+ enhancements, but useful for identifying any useful differences.
6
+
7
+ Copyright Matthew J. Smola 2015
8
+ Largely rewritten for RNAvigate by Patrick Irving 2023
9
+ """
10
+
11
+ ###########################################################################
12
+ # GPL statement: #
13
+ # #
14
+ # This program is free software: you can redistribute it and/or modify #
15
+ # it under the terms of the GNU General Public License as published by #
16
+ # the Free Software Foundation, either version 3 of the License, or #
17
+ # (at your option) any later version. #
18
+ # #
19
+ # This program is distributed in the hope that it will be useful, #
20
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of #
21
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
22
+ # GNU General Public License for more details. #
23
+ # #
24
+ # You should have received a copy of the GNU General Public License #
25
+ # along with this program. If not, see <http://www.gnu.org/licenses/>. #
26
+ ###########################################################################
27
+
28
+ from scipy.stats import zscore
29
+
30
+ from rnavigate import Sample, data, plots
31
+
32
+
33
+ class DeltaSHAPE(Sample):
34
+ """Detects meaningful differences in chemical probing reactivity
35
+
36
+ References
37
+ ----------
38
+ doi:10.1021/acs.biochem.5b00977
39
+
40
+ Algorithm
41
+ ---------
42
+ 1. Extract SHAPE-MaP sequence, normalized profile, and normalized
43
+ standard error from given samples
44
+ 2. Calculated smoothed profiles (mean) and propagate standard errors
45
+ over rolling windows
46
+ 3. Subtract raw and smoothed normalized profiles and propogate errors
47
+ 4. Calculate Z-factors for smoothed data. This is the magnitude of the
48
+ difference relative to the standard error
49
+ 5. Calculate Z-scores for smoothed data. This is the magnitude of the
50
+ difference in standard deviations from the mean difference
51
+ 6. Call sites. Called sites must have # nucleotides that pass Z-factor
52
+ and Z-score thresholds per window.
53
+
54
+ Smoothing window size, Z factor threshold, Z score threshold, site-calling
55
+ window size and minimum nucleotides per site can be specified.
56
+ """
57
+
58
+ def __init__(
59
+ self,
60
+ sample1,
61
+ sample2,
62
+ profile="shapemap",
63
+ smoothing_window=3,
64
+ zf_coeff=1.96,
65
+ ss_thresh=1,
66
+ site_window=3,
67
+ site_nts=2,
68
+ ):
69
+ """Performs DeltaSHAPE analysis between samples 1 and 2
70
+
71
+ Parameters
72
+ ----------
73
+ sample1 : rnavigate.Sample
74
+ First sample to compare
75
+ sample2 : rnavigate.Sample
76
+ Second sample to compare
77
+ profile : str, default="shapemap"
78
+ Data keyword pointing to SHAPE-MaP data in samples 1 and 2
79
+ smoothing_window : int, default=3
80
+ Size of windows for data smoothing
81
+ zf_coeff : float, default=1.96
82
+ Sites must have a difference more than zf_coeff standard errors
83
+ ss_thresh : int, default=1
84
+ Sites must have a difference that is ss_thresh standard
85
+ deviations from the mean difference
86
+ site_window : int, default=3
87
+ Number of nucleotides to include when calling sites
88
+ site_nts : int, default=2
89
+ Number of nts within site_window that must pass thresholds
90
+ """
91
+ self.parameters = {}
92
+ profile_1 = sample1.get_data(profile)
93
+ profile_1 = profile_1.get_aligned_data(
94
+ data.SequenceAlignment(profile_1, profile_1)
95
+ )
96
+ profile_2 = sample2.get_data(profile)
97
+ profile_2 = profile_2.get_aligned_data(
98
+ data.SequenceAlignment(profile_2, profile_1)
99
+ )
100
+ super().__init__(
101
+ sample=f"{sample1.sample} vs. {sample2.sample}",
102
+ inherit=[sample1, sample2],
103
+ deltashape=DeltaSHAPEProfile((profile_1, profile_2)),
104
+ profile_1=profile_1,
105
+ profile_2=profile_2,
106
+ )
107
+ self.calculate_deltashape(
108
+ smoothing_window=smoothing_window,
109
+ zf_coeff=zf_coeff,
110
+ ss_thresh=ss_thresh,
111
+ site_window=site_window,
112
+ site_nts=site_nts,
113
+ )
114
+
115
+ def calculate_deltashape(
116
+ self, smoothing_window=3, zf_coeff=1.96, ss_thresh=1, site_window=2, site_nts=3
117
+ ):
118
+ """Calculate or recalculate deltaSHAPE profile and called sites
119
+
120
+ Parameters
121
+ ----------
122
+ smoothing_window : int, default=3
123
+ Size of windows for data smoothing
124
+ zf_coeff : float, default=1.96
125
+ Sites must have a difference more than zf_coeff standard errors
126
+ ss_thresh : int, default=1
127
+ Sites must have a difference that is ss_thresh standard
128
+ deviations from the mean difference
129
+ site_window : int, default=3
130
+ Number of nucleotides to include when calling sites
131
+ site_nts : int, default=2
132
+ Number of nts within site_window that must pass thresholds
133
+ """
134
+ self.parameters = {
135
+ "smoothing_window": smoothing_window,
136
+ "zf_coeff": zf_coeff,
137
+ "ss_thresh": ss_thresh,
138
+ "site_nts": site_nts,
139
+ "site_window": site_window,
140
+ }
141
+ deltashape = self.data["deltashape"]
142
+ deltashape.calculate_deltashape(
143
+ smoothing_window=smoothing_window,
144
+ zf_coeff=zf_coeff,
145
+ ss_thresh=ss_thresh,
146
+ site_window=site_window,
147
+ site_nts=site_nts,
148
+ )
149
+ self.set_data("protections", deltashape.get_protections_annotation())
150
+ self.set_data("enhancements", deltashape.get_enhancements_annotation())
151
+
152
+ def plot(self, region="all"):
153
+ """Plot the deltaSHAPE result
154
+
155
+ Parameters
156
+ ----------
157
+ region : list of 2 integers, default="all"
158
+ start and end positions to plot
159
+
160
+ Returns
161
+ -------
162
+ rnav.plots.Profile
163
+ The plot object
164
+ """
165
+ plot = plots.Profile(1, self.data["deltashape"].length, region=region)
166
+ plot.plot_data(
167
+ profile=self.data["deltashape"],
168
+ annotations=self.get_data(["protections", "enhancements"]),
169
+ domains=None,
170
+ plot_error=True,
171
+ label=self.sample,
172
+ )
173
+ plot.set_figure_size()
174
+ return plot
175
+
176
+
177
+ class DeltaSHAPEProfile(data.Profile):
178
+ """Profile data class for performing deltaSHAPE analysis"""
179
+
180
+ def __init__(
181
+ self,
182
+ input_data,
183
+ metric="Smooth_diff",
184
+ metric_defaults=None,
185
+ sequence=None,
186
+ name=None,
187
+ **kwargs,
188
+ ):
189
+ """Create the deltaSHAPE Profile
190
+
191
+ Parameters
192
+ ----------
193
+ input_data : tuple of rnavigate.Profile or pd.DataFrame
194
+ If tuple of Profiles, the unified Dataframe will be created
195
+ metric : str, default="Smooth_diff"
196
+ The metric to use for the profile
197
+ metric_defaults : dict, default=None
198
+ Default settings for the metric
199
+ sequence : str, default=None
200
+ The sequence of the profile
201
+ name : str, default=None
202
+ The name of the profile
203
+ **kwargs
204
+ Additional keyword arguments to pass to data.Profile
205
+ """
206
+ # STEP ONE
207
+ # extract relevant information from sample 1 and 2 profiles
208
+ # sequence, normalized profile, normalized standard error
209
+ columns = ["Nucleotide", "Sequence", "Norm_profile", "Norm_stderr"]
210
+ if isinstance(input_data, (tuple, list)):
211
+ profile1, profile2 = input_data
212
+ df_1 = profile1.data[columns]
213
+ df_2 = profile2.data[columns].rename(columns={"Sequence": "Sequence_2"})
214
+ input_data = df_1.merge(
215
+ df_2, how="left", on=["Nucleotide"], suffixes=("_1", "_2")
216
+ )
217
+ if metric_defaults is None:
218
+ metric_defaults = {}
219
+ metric_defaults = {
220
+ "Smooth_diff": {
221
+ "metric_column": "Smooth_diff",
222
+ "error_column": "Smooth_diff_stderr",
223
+ "color_column": "Class",
224
+ "cmap": ["lightgrey", "#7F3B95", "#3EB452"],
225
+ "normalization": "none",
226
+ "values": None,
227
+ "extend": "neither",
228
+ "title": "deltaSHAPE",
229
+ "ticks": [0, 1, 2],
230
+ "tick_labels": ["other", "protection", "enhancement"],
231
+ "alpha": 0.7,
232
+ },
233
+ } | metric_defaults
234
+ super().__init__(
235
+ input_data=input_data,
236
+ metric=metric,
237
+ metric_defaults=metric_defaults,
238
+ sequence=sequence,
239
+ name=name,
240
+ **kwargs,
241
+ )
242
+
243
+ def calculate_deltashape(
244
+ self, smoothing_window=3, zf_coeff=1.96, ss_thresh=1, site_window=3, site_nts=2
245
+ ):
246
+ """Calculate the deltaSHAPE profile metrics
247
+
248
+ Parameters
249
+ ----------
250
+ smoothing_window : int, default=3
251
+ Size of windows for data smoothing
252
+ zf_coeff : float, default=1.96
253
+ Sites must have a difference more than zf_coeff standard errors
254
+ ss_thresh : int, default=1
255
+ Sites must have a difference that is ss_thresh standard
256
+ deviations from the mean difference
257
+ site_window : int, default=3
258
+ Number of nucleotides to include when calling sites
259
+ site_nts : int, default=2
260
+ Number of nts within site_window that must pass thresholds
261
+ """
262
+
263
+ # STEP TWO
264
+ # smooth data and errors
265
+ def propagate_errors(errors):
266
+ errors = errors[~errors.isna()]
267
+ return (errors**2).sum() ** 0.5 / len(errors)
268
+
269
+ self.calculate_windows(
270
+ column="Norm_profile_1",
271
+ window=smoothing_window,
272
+ new_name="Smooth_profile_1",
273
+ method="mean",
274
+ minimum_points=1,
275
+ mask_na=True,
276
+ )
277
+ self.calculate_windows(
278
+ column="Norm_stderr_1",
279
+ window=smoothing_window,
280
+ new_name="Smooth_stderr_1",
281
+ method=propagate_errors,
282
+ minimum_points=1,
283
+ mask_na=True,
284
+ )
285
+ self.calculate_windows(
286
+ column="Norm_profile_2",
287
+ window=smoothing_window,
288
+ new_name="Smooth_profile_2",
289
+ method="mean",
290
+ minimum_points=1,
291
+ mask_na=True,
292
+ )
293
+ self.calculate_windows(
294
+ column="Norm_stderr_2",
295
+ window=smoothing_window,
296
+ new_name="Smooth_stderr_2",
297
+ method=propagate_errors,
298
+ minimum_points=1,
299
+ mask_na=True,
300
+ )
301
+
302
+ # STEP THREE
303
+ # subtract raw and smoothed data
304
+ self.data["Diff_profile"] = self.data.eval("Norm_profile_1 - Norm_profile_2")
305
+ self.data["Diff_stderr"] = self.data.eval("Norm_stderr_1 + Norm_stderr_2")
306
+ self.data["Smooth_diff"] = self.data.eval("Smooth_profile_1 - Smooth_profile_2")
307
+ self.data["Smooth_diff_stderr"] = self.data.eval(
308
+ "Smooth_stderr_1 + Smooth_stderr_2"
309
+ )
310
+ self.data["Positive"] = self.data["Smooth_diff"] > 0
311
+
312
+ # STEP FOUR
313
+ # calculate Z-factors from smoothed data and smoothed errs
314
+ confidence_interval = self.data.eval(
315
+ f"Smooth_stderr_1 + Smooth_stderr_2 * {zf_coeff}"
316
+ )
317
+ difference = self.data["Smooth_diff"].abs()
318
+ self.data["Z_factor"] = 1 - (confidence_interval / difference)
319
+
320
+ # STEP FIVE
321
+ # calculate Z-scores from difference of smoothed data
322
+ self.data["Z_score"] = abs(zscore(self.data["Smooth_diff"], nan_policy="omit"))
323
+
324
+ # STEP SIX
325
+ # identify site_window nt windows where site_nts are significant
326
+ def determine_significance(series):
327
+ df = self.data.loc[series.index, ["Z_factor", "Z_score"]]
328
+ significant = df["Z_factor"] > 0
329
+ significant &= df["Z_score"] > ss_thresh
330
+ return sum(significant) >= site_nts
331
+
332
+ windows = self.data["Nucleotide"].rolling(site_window, center=True)
333
+ self.data["Significant"] = windows.apply(determine_significance)
334
+ self.data["Significant"] = self.data["Significant"].fillna(0).astype(bool)
335
+ self.data["Class"] = 0
336
+ self.data.loc[self.data.eval("Significant & ~ Positive"), "Class"] = 1
337
+ self.data.loc[self.data.eval("Significant & Positive"), "Class"] = 2
338
+
339
+ def get_protections_annotation(self):
340
+ """Get an annotations object for the significant protections"""
341
+ is_protected = self.data.eval("Significant & ~ Positive")
342
+ return data.Annotation.from_boolean_array(
343
+ values=is_protected,
344
+ window=1,
345
+ annotation_type="spans",
346
+ name="Protections",
347
+ sequence=self.sequence,
348
+ color="#7F3B95",
349
+ )
350
+
351
+ def get_enhancements_annotation(self):
352
+ """Get an annotations object for the significant enhancements"""
353
+ is_enhanced = self.data.eval("Significant & Positive")
354
+ return data.Annotation.from_boolean_array(
355
+ values=is_enhanced,
356
+ window=1,
357
+ annotation_type="spans",
358
+ name="Enhancements",
359
+ sequence=self.sequence,
360
+ color="#3EB452",
361
+ )