pylocuszoom 0.6.0__py3-none-any.whl → 0.8.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.
- pylocuszoom/__init__.py +15 -0
- pylocuszoom/backends/__init__.py +116 -17
- pylocuszoom/backends/base.py +363 -60
- pylocuszoom/backends/bokeh_backend.py +77 -15
- pylocuszoom/backends/hover.py +198 -0
- pylocuszoom/backends/matplotlib_backend.py +263 -3
- pylocuszoom/backends/plotly_backend.py +73 -16
- pylocuszoom/ensembl.py +476 -0
- pylocuszoom/eqtl.py +15 -19
- pylocuszoom/finemapping.py +17 -26
- pylocuszoom/forest.py +9 -11
- pylocuszoom/gene_track.py +161 -135
- pylocuszoom/loaders.py +3 -1
- pylocuszoom/phewas.py +10 -11
- pylocuszoom/plotter.py +120 -194
- pylocuszoom/recombination.py +19 -3
- pylocuszoom/utils.py +52 -0
- pylocuszoom/validation.py +172 -0
- {pylocuszoom-0.6.0.dist-info → pylocuszoom-0.8.0.dist-info}/METADATA +46 -25
- pylocuszoom-0.8.0.dist-info/RECORD +29 -0
- pylocuszoom-0.6.0.dist-info/RECORD +0 -26
- {pylocuszoom-0.6.0.dist-info → pylocuszoom-0.8.0.dist-info}/WHEEL +0 -0
- {pylocuszoom-0.6.0.dist-info → pylocuszoom-0.8.0.dist-info}/licenses/LICENSE.md +0 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"""DataFrame validation builder for pyLocusZoom.
|
|
2
|
+
|
|
3
|
+
Provides a fluent API for validating pandas DataFrames with composable
|
|
4
|
+
validation rules. Accumulates all validation errors before raising.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import List, Optional
|
|
8
|
+
|
|
9
|
+
import pandas as pd
|
|
10
|
+
from pandas.api.types import is_numeric_dtype
|
|
11
|
+
|
|
12
|
+
from .utils import ValidationError
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DataFrameValidator:
|
|
16
|
+
"""Builder for composable DataFrame validation.
|
|
17
|
+
|
|
18
|
+
Validates DataFrames with method chaining and accumulates all errors
|
|
19
|
+
before raising. This enables clear, readable validation code with
|
|
20
|
+
comprehensive error messages.
|
|
21
|
+
|
|
22
|
+
Example:
|
|
23
|
+
>>> validator = DataFrameValidator(df, name="gwas_df")
|
|
24
|
+
>>> validator.require_columns(["chr", "pos", "p"])
|
|
25
|
+
... .require_numeric(["pos", "p"])
|
|
26
|
+
... .require_range("p", min_val=0, max_val=1)
|
|
27
|
+
... .validate()
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(self, df: pd.DataFrame, name: str = "DataFrame"):
|
|
31
|
+
"""Initialize validator.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
df: DataFrame to validate.
|
|
35
|
+
name: Name for error messages (e.g., "gwas_df", "genes_df").
|
|
36
|
+
"""
|
|
37
|
+
self._df = df
|
|
38
|
+
self._name = name
|
|
39
|
+
self._errors: List[str] = []
|
|
40
|
+
|
|
41
|
+
def require_columns(self, columns: List[str]) -> "DataFrameValidator":
|
|
42
|
+
"""Check that required columns exist in DataFrame.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
columns: List of required column names.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
Self for method chaining.
|
|
49
|
+
"""
|
|
50
|
+
if not columns:
|
|
51
|
+
return self
|
|
52
|
+
|
|
53
|
+
missing = [col for col in columns if col not in self._df.columns]
|
|
54
|
+
if missing:
|
|
55
|
+
available = list(self._df.columns)
|
|
56
|
+
self._errors.append(f"Missing columns: {missing}. Available: {available}")
|
|
57
|
+
|
|
58
|
+
return self
|
|
59
|
+
|
|
60
|
+
def require_numeric(self, columns: List[str]) -> "DataFrameValidator":
|
|
61
|
+
"""Check that columns have numeric dtype.
|
|
62
|
+
|
|
63
|
+
Skips columns that don't exist (checked separately by require_columns).
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
columns: List of column names that should be numeric.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
Self for method chaining.
|
|
70
|
+
"""
|
|
71
|
+
for col in columns:
|
|
72
|
+
# Skip missing columns - let require_columns handle that
|
|
73
|
+
if col not in self._df.columns:
|
|
74
|
+
continue
|
|
75
|
+
|
|
76
|
+
if not is_numeric_dtype(self._df[col]):
|
|
77
|
+
actual_dtype = self._df[col].dtype
|
|
78
|
+
self._errors.append(
|
|
79
|
+
f"Column '{col}' must be numeric, got {actual_dtype}"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
return self
|
|
83
|
+
|
|
84
|
+
def require_range(
|
|
85
|
+
self,
|
|
86
|
+
column: str,
|
|
87
|
+
min_val: Optional[float] = None,
|
|
88
|
+
max_val: Optional[float] = None,
|
|
89
|
+
exclusive_min: bool = False,
|
|
90
|
+
exclusive_max: bool = False,
|
|
91
|
+
) -> "DataFrameValidator":
|
|
92
|
+
"""Check that column values are within specified range.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
column: Column name to check.
|
|
96
|
+
min_val: Minimum allowed value (inclusive by default).
|
|
97
|
+
max_val: Maximum allowed value (inclusive by default).
|
|
98
|
+
exclusive_min: If True, minimum is exclusive (values must be > min_val).
|
|
99
|
+
exclusive_max: If True, maximum is exclusive (values must be < max_val).
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
Self for method chaining.
|
|
103
|
+
"""
|
|
104
|
+
# Skip missing columns
|
|
105
|
+
if column not in self._df.columns:
|
|
106
|
+
return self
|
|
107
|
+
|
|
108
|
+
col_data = self._df[column]
|
|
109
|
+
|
|
110
|
+
# Check minimum bound
|
|
111
|
+
if min_val is not None:
|
|
112
|
+
if exclusive_min:
|
|
113
|
+
invalid_count = (col_data <= min_val).sum()
|
|
114
|
+
if invalid_count > 0:
|
|
115
|
+
self._errors.append(
|
|
116
|
+
f"Column '{column}': {invalid_count} values <= {min_val}"
|
|
117
|
+
)
|
|
118
|
+
else:
|
|
119
|
+
invalid_count = (col_data < min_val).sum()
|
|
120
|
+
if invalid_count > 0:
|
|
121
|
+
self._errors.append(
|
|
122
|
+
f"Column '{column}': {invalid_count} values < {min_val}"
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# Check maximum bound
|
|
126
|
+
if max_val is not None:
|
|
127
|
+
if exclusive_max:
|
|
128
|
+
invalid_count = (col_data >= max_val).sum()
|
|
129
|
+
if invalid_count > 0:
|
|
130
|
+
self._errors.append(
|
|
131
|
+
f"Column '{column}': {invalid_count} values >= {max_val}"
|
|
132
|
+
)
|
|
133
|
+
else:
|
|
134
|
+
invalid_count = (col_data > max_val).sum()
|
|
135
|
+
if invalid_count > 0:
|
|
136
|
+
self._errors.append(
|
|
137
|
+
f"Column '{column}': {invalid_count} values > {max_val}"
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
return self
|
|
141
|
+
|
|
142
|
+
def require_not_null(self, columns: List[str]) -> "DataFrameValidator":
|
|
143
|
+
"""Check that columns have no null (NaN or None) values.
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
columns: List of column names to check for nulls.
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
Self for method chaining.
|
|
150
|
+
"""
|
|
151
|
+
for col in columns:
|
|
152
|
+
# Skip missing columns
|
|
153
|
+
if col not in self._df.columns:
|
|
154
|
+
continue
|
|
155
|
+
|
|
156
|
+
null_count = self._df[col].isna().sum()
|
|
157
|
+
if null_count > 0:
|
|
158
|
+
self._errors.append(f"Column '{col}' has {null_count} null values")
|
|
159
|
+
|
|
160
|
+
return self
|
|
161
|
+
|
|
162
|
+
def validate(self) -> None:
|
|
163
|
+
"""Raise ValidationError if any validation rules failed.
|
|
164
|
+
|
|
165
|
+
Raises:
|
|
166
|
+
ValidationError: If any validation errors were accumulated.
|
|
167
|
+
Error message includes all accumulated errors.
|
|
168
|
+
"""
|
|
169
|
+
if self._errors:
|
|
170
|
+
error_msg = f"{self._name} validation failed:\n"
|
|
171
|
+
error_msg += "\n".join(f" - {error}" for error in self._errors)
|
|
172
|
+
raise ValidationError(error_msg)
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pylocuszoom
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Publication-ready regional association plots with LD coloring, gene tracks, and recombination overlays
|
|
5
5
|
Project-URL: Homepage, https://github.com/michael-denyer/pylocuszoom
|
|
6
6
|
Project-URL: Documentation, https://github.com/michael-denyer/pylocuszoom#readme
|
|
7
7
|
Project-URL: Repository, https://github.com/michael-denyer/pylocuszoom
|
|
8
|
-
Author: Michael Denyer
|
|
8
|
+
Author-email: Michael Denyer <code.denyer@gmail.com>
|
|
9
9
|
License-Expression: GPL-3.0-or-later
|
|
10
10
|
License-File: LICENSE.md
|
|
11
11
|
Keywords: genetics,gwas,locus-zoom,locuszoom,regional-plot,visualization
|
|
12
|
-
Classifier: Development Status ::
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
13
|
Classifier: Intended Audience :: Science/Research
|
|
14
14
|
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -44,20 +44,18 @@ Requires-Dist: pyspark>=3.0.0; extra == 'spark'
|
|
|
44
44
|
Description-Content-Type: text/markdown
|
|
45
45
|
|
|
46
46
|
[](https://github.com/michael-denyer/pyLocusZoom/actions/workflows/ci.yml)
|
|
47
|
-
[](https://codecov.io/gh/michael-denyer/pyLocusZoom)
|
|
48
47
|
[](https://pypi.org/project/pylocuszoom/)
|
|
49
|
-
[](https://anaconda.org/bioconda/pylocuszoom)
|
|
50
48
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
51
49
|
[](https://www.python.org/downloads/)
|
|
52
50
|
[](https://github.com/astral-sh/ruff)
|
|
53
51
|
[](https://matplotlib.org/)
|
|
54
|
-
[](https://plotly.com/python/)
|
|
55
53
|
[](https://bokeh.org/)
|
|
56
54
|
[](https://pandas.pydata.org/)
|
|
57
55
|
<img src="logo.svg" alt="pyLocusZoom logo" width="120" align="right">
|
|
58
56
|
# pyLocusZoom
|
|
59
57
|
|
|
60
|
-
|
|
58
|
+
Designed for publication-ready GWAS visualization with regional association plots, gene tracks, eQTL, PheWAS, fine-mapping, and forest plots.
|
|
61
59
|
|
|
62
60
|
Inspired by [LocusZoom](http://locuszoom.org/) and [locuszoomr](https://github.com/myles-lewis/locuszoomr).
|
|
63
61
|
|
|
@@ -68,20 +66,22 @@ Inspired by [LocusZoom](http://locuszoom.org/) and [locuszoomr](https://github.c
|
|
|
68
66
|
- **Multi-species support**: Built-in reference data for *Canis lupus familiaris* (CanFam3.1/CanFam4) and *Felis catus* (FelCat9), or optionally provide your own for any species
|
|
69
67
|
- **LD coloring**: SNPs colored by linkage disequilibrium (R²) with lead variant
|
|
70
68
|
- **Gene tracks**: Annotated gene/exon positions below the association plot
|
|
71
|
-
- **Recombination rate**:
|
|
72
|
-
- **SNP labels (matplotlib)**: Automatic labeling of
|
|
73
|
-
- **
|
|
69
|
+
- **Recombination rate**: Optional overlay across region (*Canis lupus familiaris* built-in, not shown in example image)
|
|
70
|
+
- **SNP labels (matplotlib)**: Automatic labeling of top SNPs by p-value (RS IDs)
|
|
71
|
+
- **Hover tooltips (Plotly and Bokeh)**: Detailed SNP data on hover
|
|
74
72
|
|
|
75
|
-

|
|
73
|
+

|
|
74
|
+
*Regional association plot with LD coloring, gene/exon track, and top SNP labels (recombination overlay disabled in example).*
|
|
76
75
|
|
|
77
76
|
2. **Stacked plots**: Compare multiple GWAS/phenotypes vertically
|
|
78
77
|
3. **eQTL plot**: Expression QTL data aligned with association plots and gene tracks
|
|
79
78
|
4. **Fine-mapping plots**: Visualize SuSiE credible sets with posterior inclusion probabilities
|
|
80
79
|
5. **PheWAS plots**: Phenome-wide association study visualization across multiple phenotypes
|
|
81
80
|
6. **Forest plots**: Meta-analysis effect size visualization with confidence intervals
|
|
82
|
-
7. **Multiple
|
|
81
|
+
7. **Multiple backends**: matplotlib (publication-ready), plotly (interactive), bokeh (dashboard integration)
|
|
83
82
|
8. **Pandas and PySpark support**: Works with both Pandas and PySpark DataFrames for large-scale genomics data
|
|
84
83
|
9. **Convenience data file loaders**: Load and validate common GWAS, eQTL and fine-mapping file formats
|
|
84
|
+
10. **Automatic gene annotations**: Fetch gene/exon data from Ensembl REST API with caching (human, mouse, rat, canine, feline, and any Ensembl species)
|
|
85
85
|
|
|
86
86
|
## Installation
|
|
87
87
|
|
|
@@ -181,28 +181,46 @@ fig = plotter.plot(
|
|
|
181
181
|
)
|
|
182
182
|
```
|
|
183
183
|
|
|
184
|
+
## Automatic Gene Annotations
|
|
185
|
+
|
|
186
|
+
pyLocusZoom can automatically fetch gene annotations from Ensembl for any species:
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
# Enable automatic gene fetching
|
|
190
|
+
plotter = LocusZoomPlotter(species="human", auto_genes=True)
|
|
191
|
+
|
|
192
|
+
# No need to provide genes_df - fetched automatically
|
|
193
|
+
fig = plotter.plot(gwas_df, chrom=13, start=32000000, end=33000000)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Supported species aliases: `human`, `mouse`, `rat`, `canine`/`dog`, `feline`/`cat`, or any Ensembl species name.
|
|
197
|
+
Data is cached locally for fast subsequent plots. Maximum region size is 5Mb (Ensembl API limit).
|
|
198
|
+
|
|
184
199
|
## Backends
|
|
185
200
|
|
|
186
|
-
pyLocusZoom supports multiple rendering backends:
|
|
201
|
+
pyLocusZoom supports multiple rendering backends (set at initialization):
|
|
187
202
|
|
|
188
203
|
```python
|
|
189
204
|
# Static publication-quality plot (default)
|
|
190
|
-
|
|
205
|
+
plotter = LocusZoomPlotter(species="canine", backend="matplotlib")
|
|
206
|
+
fig = plotter.plot(gwas_df, chrom=1, start=1000000, end=2000000)
|
|
191
207
|
fig.savefig("plot.png", dpi=150)
|
|
192
208
|
|
|
193
209
|
# Interactive Plotly (hover tooltips, pan/zoom)
|
|
194
|
-
|
|
210
|
+
plotter = LocusZoomPlotter(species="canine", backend="plotly")
|
|
211
|
+
fig = plotter.plot(gwas_df, chrom=1, start=1000000, end=2000000)
|
|
195
212
|
fig.write_html("plot.html")
|
|
196
213
|
|
|
197
214
|
# Interactive Bokeh (dashboard-ready)
|
|
198
|
-
|
|
215
|
+
plotter = LocusZoomPlotter(species="canine", backend="bokeh")
|
|
216
|
+
fig = plotter.plot(gwas_df, chrom=1, start=1000000, end=2000000)
|
|
199
217
|
```
|
|
200
218
|
|
|
201
219
|
| Backend | Output | Best For | Features |
|
|
202
220
|
|---------|--------|----------|----------|
|
|
203
|
-
| `matplotlib` | Static PNG/PDF/SVG |
|
|
204
|
-
| `plotly` | Interactive HTML | Web reports,
|
|
205
|
-
| `bokeh` | Interactive HTML |
|
|
221
|
+
| `matplotlib` | Static PNG/PDF/SVG | Publication-ready figures | Full feature set with SNP labels |
|
|
222
|
+
| `plotly` | Interactive HTML | Web reports, exploration | Hover tooltips, pan/zoom |
|
|
223
|
+
| `bokeh` | Interactive HTML | Dashboard integration | Hover tooltips, pan/zoom |
|
|
206
224
|
|
|
207
225
|
> **Note:** All backends support scatter plots, gene tracks, recombination overlay, and LD legend. SNP labels (auto-positioned with adjustText) are matplotlib-only; interactive backends use hover tooltips instead.
|
|
208
226
|
|
|
@@ -221,7 +239,8 @@ fig = plotter.plot_stacked(
|
|
|
221
239
|
)
|
|
222
240
|
```
|
|
223
241
|
|
|
224
|
-

|
|
242
|
+

|
|
243
|
+
*Stacked plot comparing two phenotypes with LD coloring and shared gene track.*
|
|
225
244
|
|
|
226
245
|
## eQTL Overlay
|
|
227
246
|
|
|
@@ -244,6 +263,7 @@ fig = plotter.plot_stacked(
|
|
|
244
263
|
```
|
|
245
264
|
|
|
246
265
|

|
|
266
|
+
*eQTL overlay with effect direction (up/down triangles) and magnitude binning.*
|
|
247
267
|
|
|
248
268
|
## Fine-mapping Visualization
|
|
249
269
|
|
|
@@ -266,6 +286,7 @@ fig = plotter.plot_stacked(
|
|
|
266
286
|
```
|
|
267
287
|
|
|
268
288
|

|
|
289
|
+
*Fine-mapping visualization with PIP line and credible set coloring (CS1/CS2).*
|
|
269
290
|
|
|
270
291
|
## PheWAS Plots
|
|
271
292
|
|
|
@@ -286,6 +307,7 @@ fig = plotter.plot_phewas(
|
|
|
286
307
|
```
|
|
287
308
|
|
|
288
309
|

|
|
310
|
+
*PheWAS plot showing associations across phenotype categories with significance threshold.*
|
|
289
311
|
|
|
290
312
|
## Forest Plots
|
|
291
313
|
|
|
@@ -308,19 +330,18 @@ fig = plotter.plot_forest(
|
|
|
308
330
|
```
|
|
309
331
|
|
|
310
332
|

|
|
333
|
+
*Forest plot with effect sizes, confidence intervals, and weight-proportional markers.*
|
|
311
334
|
|
|
312
335
|
## PySpark Support
|
|
313
336
|
|
|
314
|
-
For large-scale genomics data,
|
|
337
|
+
For large-scale genomics data, convert PySpark DataFrames with `to_pandas()` before plotting:
|
|
315
338
|
|
|
316
339
|
```python
|
|
317
340
|
from pylocuszoom import LocusZoomPlotter, to_pandas
|
|
318
341
|
|
|
319
|
-
# PySpark DataFrame (
|
|
320
|
-
fig = plotter.plot(spark_gwas_df, chrom=1, start=1000000, end=2000000)
|
|
321
|
-
|
|
322
|
-
# Or convert manually with sampling for very large data
|
|
342
|
+
# Convert PySpark DataFrame (optionally sampled for very large data)
|
|
323
343
|
pandas_df = to_pandas(spark_gwas_df, sample_size=100000)
|
|
344
|
+
fig = plotter.plot(pandas_df, chrom=1, start=1000000, end=2000000)
|
|
324
345
|
```
|
|
325
346
|
|
|
326
347
|
Install PySpark support: `uv add pylocuszoom[spark]`
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
pylocuszoom/__init__.py,sha256=UtrNrjV0b0frxv3Zl4jw5D8aTMbNSE55j-PPkd8rz28,5585
|
|
2
|
+
pylocuszoom/colors.py,sha256=B28rfhWwGZ-e6Q-F43iXxC6NZpjUo0yWk4S_-vp9ZvU,7686
|
|
3
|
+
pylocuszoom/ensembl.py,sha256=q767o86FdcKn4V9aK48ESFwNI7ATlaX5tnwjZReYMEw,14436
|
|
4
|
+
pylocuszoom/eqtl.py,sha256=OrpWbFMR1wKMCmfQiC-2sqYx-99TT2i1cStIrPWIUOs,5948
|
|
5
|
+
pylocuszoom/finemapping.py,sha256=ZPcnc9E6N41Su8222wCqBkB3bhhyfASvj9u9Ot4td4o,5898
|
|
6
|
+
pylocuszoom/forest.py,sha256=302gULz9I0UiwqgcB18R756OOl1aa54OsPYHc6TnxGY,1092
|
|
7
|
+
pylocuszoom/gene_track.py,sha256=PkBwfqByVxhXlAPco9-d4P5X7cTg2rrOnw7BJVx48ow,17818
|
|
8
|
+
pylocuszoom/labels.py,sha256=Ams5WVZFNVT692BRiQ5wZcdbdNEAm5xtgRwmF5u0s_A,3492
|
|
9
|
+
pylocuszoom/ld.py,sha256=64xIulpDVvbMSryWUPoCQ99Odcjwf1wejpwVr_30MLU,6412
|
|
10
|
+
pylocuszoom/loaders.py,sha256=KpWPBO0BCb2yrGTtgdiOqOuhx2YLmjK_ywmpr3onnx8,25156
|
|
11
|
+
pylocuszoom/logging.py,sha256=nZHEkbnjp8zoyWj_S-Hy9UQvUYLoMoxyiOWRozBT2dg,4987
|
|
12
|
+
pylocuszoom/phewas.py,sha256=6g2LmwA5kmxYlHgPxJvuXIMerEqfqgsrth110Y3CgVU,968
|
|
13
|
+
pylocuszoom/plotter.py,sha256=gFywhaHPuXlbKPxWaWfw7Wrw8kqPMUPzKMgDcRB6wu8,50709
|
|
14
|
+
pylocuszoom/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
+
pylocuszoom/recombination.py,sha256=97GGBLDLTlQSRMp5sLOna3mCeRxeJiiWPHrw4dBRjQs,14546
|
|
16
|
+
pylocuszoom/schemas.py,sha256=vABBBlAR1vUP6BIewZ8E-TYpacccrcxavrdIDVCrQB4,11916
|
|
17
|
+
pylocuszoom/utils.py,sha256=_rI6ov0MbsWlZGJ7ni-V4387cirmJCX6IF2JAYhBx6A,6929
|
|
18
|
+
pylocuszoom/validation.py,sha256=UInqlhOWhWaCT_mrO7O7SfB1DNIYkjvEMudy4YjtUBg,5698
|
|
19
|
+
pylocuszoom/backends/__init__.py,sha256=xefVj3jVxmYwVLLY5AZtFqTPMehQxZ2qGd-Pk7_V_Bk,4267
|
|
20
|
+
pylocuszoom/backends/base.py,sha256=PBdm9t4f_qFDMkYR5z3edW4DvpuQSCAXuaxs2qjAeH0,21034
|
|
21
|
+
pylocuszoom/backends/bokeh_backend.py,sha256=11zRhXH2guUHiaYXyd7l2IDAv6uawdRAv6dyGPkHmJc,25512
|
|
22
|
+
pylocuszoom/backends/hover.py,sha256=Hjm_jcxJL8dDxO_Ye7jeWAUcHKlbH6oO8ZfGJ2MzIFM,6564
|
|
23
|
+
pylocuszoom/backends/matplotlib_backend.py,sha256=098ITnvNrBTaEztqez_7D0sZ_rKAYIxS6EDR5Yxt8is,20924
|
|
24
|
+
pylocuszoom/backends/plotly_backend.py,sha256=A6ZuHw0wVZaIIA6FgYJ4SH-Sz59tHOtnGUl-e-2VzZM,30574
|
|
25
|
+
pylocuszoom/reference_data/__init__.py,sha256=qqHqAUt1jebGlCN3CjqW3Z-_coHVNo5K3a3bb9o83hA,109
|
|
26
|
+
pylocuszoom-0.8.0.dist-info/METADATA,sha256=VqHRvFL1Wq5OJO3B727Rl0H8UfbBPaxVIJUOSA22s5A,17866
|
|
27
|
+
pylocuszoom-0.8.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
28
|
+
pylocuszoom-0.8.0.dist-info/licenses/LICENSE.md,sha256=U2y_hv8RcN5lECA3uK88irU3ODUE1TDAPictcmnP0Q4,698
|
|
29
|
+
pylocuszoom-0.8.0.dist-info/RECORD,,
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
pylocuszoom/__init__.py,sha256=yb7NMehYOWYPPSBkO4EWwMY4NT-fj8oniNvI3h4oLL0,5219
|
|
2
|
-
pylocuszoom/colors.py,sha256=B28rfhWwGZ-e6Q-F43iXxC6NZpjUo0yWk4S_-vp9ZvU,7686
|
|
3
|
-
pylocuszoom/eqtl.py,sha256=9lZJ8jT1WEj3won6D9B54xdqUvbRvxpOitf97NCUR28,6167
|
|
4
|
-
pylocuszoom/finemapping.py,sha256=PJ4HJYeCaHZecUmADCEGQxKd9HhhjrdIA1H5LQsUmLI,6332
|
|
5
|
-
pylocuszoom/forest.py,sha256=WFX29gEcH-xS5G4kbb9J2WPcbRw7OdMegFuLqN4VfIE,1147
|
|
6
|
-
pylocuszoom/gene_track.py,sha256=VWvPY0SrVFGJprTdttJ72r3JD-r3bdRDr0HDBai0oJw,18692
|
|
7
|
-
pylocuszoom/labels.py,sha256=Ams5WVZFNVT692BRiQ5wZcdbdNEAm5xtgRwmF5u0s_A,3492
|
|
8
|
-
pylocuszoom/ld.py,sha256=64xIulpDVvbMSryWUPoCQ99Odcjwf1wejpwVr_30MLU,6412
|
|
9
|
-
pylocuszoom/loaders.py,sha256=28PqlUhbq1Y6Xzv9NFucWSAqRTqGj8h-pR7wOOmIHxI,25132
|
|
10
|
-
pylocuszoom/logging.py,sha256=nZHEkbnjp8zoyWj_S-Hy9UQvUYLoMoxyiOWRozBT2dg,4987
|
|
11
|
-
pylocuszoom/phewas.py,sha256=jrVDQvUu4rEH3YCE00LX-6STY96vMcK9xZ7AhiN9Jjo,984
|
|
12
|
-
pylocuszoom/plotter.py,sha256=ywqlLMDalzWJaeIfkK_qYh9HRWbypJf9Pgd0II8jAss,53368
|
|
13
|
-
pylocuszoom/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
-
pylocuszoom/recombination.py,sha256=_KU9zwlhjk0MfyG4_i3rS0JPj5SIWcyTxglVlF-KMP8,13826
|
|
15
|
-
pylocuszoom/schemas.py,sha256=vABBBlAR1vUP6BIewZ8E-TYpacccrcxavrdIDVCrQB4,11916
|
|
16
|
-
pylocuszoom/utils.py,sha256=fKNX9WSTbfHR1EpPYijt6ycNjXEjwzunQMHXAvHaK3s,5211
|
|
17
|
-
pylocuszoom/backends/__init__.py,sha256=7dlGvDoqMVK3fCtoMcI9zOP9qO0odQGPwfXhxnLfXfI,1196
|
|
18
|
-
pylocuszoom/backends/base.py,sha256=ll6pKxVuzMNBDGowOYcPHpFkh4vIRoD_XomXQS8pPOk,11960
|
|
19
|
-
pylocuszoom/backends/bokeh_backend.py,sha256=MQ-UJyGW46Rm6Cj6za9mPn9z8yUVnHibLrAfyNzYp-c,23851
|
|
20
|
-
pylocuszoom/backends/matplotlib_backend.py,sha256=dK3n1KSGSTg4jgnwpa_5A5UvQhbN9hdyEtuDy-uUY1I,13178
|
|
21
|
-
pylocuszoom/backends/plotly_backend.py,sha256=l6H4xabuxZPIGn4bqMb1BGRGylehklvxomun7nL8wIY,29174
|
|
22
|
-
pylocuszoom/reference_data/__init__.py,sha256=qqHqAUt1jebGlCN3CjqW3Z-_coHVNo5K3a3bb9o83hA,109
|
|
23
|
-
pylocuszoom-0.6.0.dist-info/METADATA,sha256=rSgBh890ygYNyPwv6oEBpsIU23BSevMw1Nyfhzv90Bs,16543
|
|
24
|
-
pylocuszoom-0.6.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
25
|
-
pylocuszoom-0.6.0.dist-info/licenses/LICENSE.md,sha256=U2y_hv8RcN5lECA3uK88irU3ODUE1TDAPictcmnP0Q4,698
|
|
26
|
-
pylocuszoom-0.6.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|