pylocuszoom 0.1.0__py3-none-any.whl → 0.2.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 +39 -20
- pylocuszoom/backends/__init__.py +1 -5
- pylocuszoom/backends/base.py +1 -1
- pylocuszoom/backends/bokeh_backend.py +4 -7
- pylocuszoom/backends/matplotlib_backend.py +6 -1
- pylocuszoom/backends/plotly_backend.py +11 -12
- pylocuszoom/colors.py +132 -0
- pylocuszoom/eqtl.py +3 -2
- pylocuszoom/finemapping.py +224 -0
- pylocuszoom/gene_track.py +44 -31
- pylocuszoom/labels.py +32 -33
- pylocuszoom/ld.py +8 -7
- pylocuszoom/plotter.py +381 -66
- pylocuszoom/recombination.py +14 -14
- pylocuszoom/utils.py +3 -1
- {pylocuszoom-0.1.0.dist-info → pylocuszoom-0.2.0.dist-info}/METADATA +20 -25
- pylocuszoom-0.2.0.dist-info/RECORD +21 -0
- pylocuszoom-0.1.0.dist-info/RECORD +0 -20
- {pylocuszoom-0.1.0.dist-info → pylocuszoom-0.2.0.dist-info}/WHEEL +0 -0
- {pylocuszoom-0.1.0.dist-info → pylocuszoom-0.2.0.dist-info}/licenses/LICENSE.md +0 -0
pylocuszoom/recombination.py
CHANGED
|
@@ -22,7 +22,7 @@ from .logging import logger
|
|
|
22
22
|
RECOMB_COLOR = "#7FCDFF" # Light blue
|
|
23
23
|
|
|
24
24
|
# Data sources by species
|
|
25
|
-
|
|
25
|
+
CANINE_RECOMB_URL = (
|
|
26
26
|
"https://github.com/cflerin/dog_recombination/raw/master/dog_genetic_maps.tar.gz"
|
|
27
27
|
)
|
|
28
28
|
|
|
@@ -177,11 +177,11 @@ def get_default_data_dir() -> Path:
|
|
|
177
177
|
return base / "snp-scope-plot" / "recombination_maps"
|
|
178
178
|
|
|
179
179
|
|
|
180
|
-
def
|
|
180
|
+
def download_canine_recombination_maps(
|
|
181
181
|
output_dir: Optional[str] = None,
|
|
182
182
|
force: bool = False,
|
|
183
183
|
) -> Path:
|
|
184
|
-
"""Download
|
|
184
|
+
"""Download canine recombination rate maps from Campbell et al. 2016.
|
|
185
185
|
|
|
186
186
|
Downloads from: https://github.com/cflerin/dog_recombination
|
|
187
187
|
|
|
@@ -213,22 +213,22 @@ def download_dog_recombination_maps(
|
|
|
213
213
|
# Create output directory
|
|
214
214
|
output_path.mkdir(parents=True, exist_ok=True)
|
|
215
215
|
|
|
216
|
-
logger.info("Downloading
|
|
217
|
-
logger.debug(f"Source: {
|
|
216
|
+
logger.info("Downloading canine recombination maps from GitHub...")
|
|
217
|
+
logger.debug(f"Source: {CANINE_RECOMB_URL}")
|
|
218
218
|
|
|
219
219
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
220
220
|
# Download tar.gz file
|
|
221
221
|
tar_path = Path(tmpdir) / "dog_genetic_maps.tar.gz"
|
|
222
222
|
|
|
223
223
|
try:
|
|
224
|
-
urllib.request.urlretrieve(
|
|
224
|
+
urllib.request.urlretrieve(CANINE_RECOMB_URL, tar_path)
|
|
225
225
|
except Exception as e:
|
|
226
226
|
logger.debug(f"urllib download failed: {e}")
|
|
227
227
|
logger.debug("Trying alternative method with requests...")
|
|
228
228
|
try:
|
|
229
229
|
import requests
|
|
230
230
|
|
|
231
|
-
response = requests.get(
|
|
231
|
+
response = requests.get(CANINE_RECOMB_URL, timeout=60)
|
|
232
232
|
response.raise_for_status()
|
|
233
233
|
tar_path.write_bytes(response.content)
|
|
234
234
|
except ImportError:
|
|
@@ -282,14 +282,14 @@ def download_dog_recombination_maps(
|
|
|
282
282
|
|
|
283
283
|
def load_recombination_map(
|
|
284
284
|
chrom: int,
|
|
285
|
-
species: str = "
|
|
285
|
+
species: str = "canine",
|
|
286
286
|
data_dir: Optional[str] = None,
|
|
287
287
|
) -> pd.DataFrame:
|
|
288
288
|
"""Load recombination map for a specific chromosome.
|
|
289
289
|
|
|
290
290
|
Args:
|
|
291
|
-
chrom: Chromosome number (1-38 for
|
|
292
|
-
species: Species name ('
|
|
291
|
+
chrom: Chromosome number (1-38 for canine, 1-18 for feline) or 'X'.
|
|
292
|
+
species: Species name ('canine', 'feline').
|
|
293
293
|
data_dir: Directory containing recombination maps.
|
|
294
294
|
|
|
295
295
|
Returns:
|
|
@@ -326,7 +326,7 @@ def get_recombination_rate_for_region(
|
|
|
326
326
|
chrom: int,
|
|
327
327
|
start: int,
|
|
328
328
|
end: int,
|
|
329
|
-
species: str = "
|
|
329
|
+
species: str = "canine",
|
|
330
330
|
data_dir: Optional[str] = None,
|
|
331
331
|
genome_build: Optional[str] = None,
|
|
332
332
|
) -> pd.DataFrame:
|
|
@@ -336,7 +336,7 @@ def get_recombination_rate_for_region(
|
|
|
336
336
|
chrom: Chromosome number.
|
|
337
337
|
start: Start position (bp).
|
|
338
338
|
end: End position (bp).
|
|
339
|
-
species: Species name ('
|
|
339
|
+
species: Species name ('canine', 'feline').
|
|
340
340
|
data_dir: Directory containing recombination maps.
|
|
341
341
|
genome_build: Target genome build (e.g., "canfam4"). If specified and
|
|
342
342
|
different from source data (CanFam3.1), coordinates are lifted over.
|
|
@@ -345,7 +345,7 @@ def get_recombination_rate_for_region(
|
|
|
345
345
|
DataFrame with pos and rate columns for the region.
|
|
346
346
|
|
|
347
347
|
Note:
|
|
348
|
-
Built-in
|
|
348
|
+
Built-in canine recombination maps are in CanFam3.1 coordinates.
|
|
349
349
|
If genome_build="canfam4", positions are automatically lifted over.
|
|
350
350
|
This requires pyliftover: pip install pyliftover
|
|
351
351
|
"""
|
|
@@ -353,7 +353,7 @@ def get_recombination_rate_for_region(
|
|
|
353
353
|
|
|
354
354
|
# Liftover if needed
|
|
355
355
|
build = _normalize_build(genome_build)
|
|
356
|
-
if species == "
|
|
356
|
+
if species == "canine" and build == "canfam4":
|
|
357
357
|
logger.debug(f"Lifting over recombination map for chr{chrom} to CanFam4")
|
|
358
358
|
df = liftover_recombination_map(
|
|
359
359
|
df, from_build="canfam3", to_build="canfam4", chrom=chrom
|
pylocuszoom/utils.py
CHANGED
|
@@ -29,7 +29,9 @@ def is_spark_dataframe(df: Any) -> bool:
|
|
|
29
29
|
True if PySpark DataFrame, False otherwise.
|
|
30
30
|
"""
|
|
31
31
|
# Check class name to avoid importing pyspark
|
|
32
|
-
return type(df).__name__ == "DataFrame" and type(df).__module__.startswith(
|
|
32
|
+
return type(df).__name__ == "DataFrame" and type(df).__module__.startswith(
|
|
33
|
+
"pyspark"
|
|
34
|
+
)
|
|
33
35
|
|
|
34
36
|
|
|
35
37
|
def to_pandas(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pylocuszoom
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Regional association plots for GWAS results with LD coloring, gene tracks, and recombination rate overlays
|
|
5
5
|
Project-URL: Homepage, https://github.com/michael-denyer/pylocuszoom
|
|
6
6
|
Project-URL: Documentation, https://github.com/michael-denyer/pylocuszoom#readme
|
|
@@ -71,6 +71,8 @@ Inspired by [LocusZoom](http://locuszoom.org/) and [locuszoomr](https://github.c
|
|
|
71
71
|
- **eQTL overlay**: Expression QTL data as separate panel
|
|
72
72
|
- **PySpark support**: Handles large-scale genomics DataFrames
|
|
73
73
|
|
|
74
|
+

|
|
75
|
+
|
|
74
76
|
## Installation
|
|
75
77
|
|
|
76
78
|
```bash
|
|
@@ -88,8 +90,8 @@ pip install pylocuszoom
|
|
|
88
90
|
```python
|
|
89
91
|
from pylocuszoom import LocusZoomPlotter
|
|
90
92
|
|
|
91
|
-
# Initialize plotter (loads reference data for
|
|
92
|
-
plotter = LocusZoomPlotter(species="
|
|
93
|
+
# Initialize plotter (loads reference data for canine)
|
|
94
|
+
plotter = LocusZoomPlotter(species="canine")
|
|
93
95
|
|
|
94
96
|
# Create regional plot
|
|
95
97
|
fig = plotter.plot(
|
|
@@ -109,7 +111,7 @@ fig.savefig("regional_plot.png", dpi=150)
|
|
|
109
111
|
from pylocuszoom import LocusZoomPlotter
|
|
110
112
|
|
|
111
113
|
plotter = LocusZoomPlotter(
|
|
112
|
-
species="
|
|
114
|
+
species="canine", # or "feline", or None for custom
|
|
113
115
|
plink_path="/path/to/plink", # Optional, auto-detects if on PATH
|
|
114
116
|
)
|
|
115
117
|
|
|
@@ -134,10 +136,10 @@ fig = plotter.plot(
|
|
|
134
136
|
|
|
135
137
|
## Genome Builds
|
|
136
138
|
|
|
137
|
-
The default genome build for
|
|
139
|
+
The default genome build for canine is CanFam3.1. For CanFam4 data:
|
|
138
140
|
|
|
139
141
|
```python
|
|
140
|
-
plotter = LocusZoomPlotter(species="
|
|
142
|
+
plotter = LocusZoomPlotter(species="canine", genome_build="canfam4")
|
|
141
143
|
```
|
|
142
144
|
|
|
143
145
|
Recombination maps are automatically lifted over from CanFam3.1 to CanFam4 coordinates using the UCSC liftOver chain file.
|
|
@@ -145,8 +147,8 @@ Recombination maps are automatically lifted over from CanFam3.1 to CanFam4 coord
|
|
|
145
147
|
## Using with Other Species
|
|
146
148
|
|
|
147
149
|
```python
|
|
148
|
-
#
|
|
149
|
-
plotter = LocusZoomPlotter(species="
|
|
150
|
+
# Feline (LD and gene tracks, user provides recombination data)
|
|
151
|
+
plotter = LocusZoomPlotter(species="feline")
|
|
150
152
|
|
|
151
153
|
# Custom species (provide all reference data)
|
|
152
154
|
plotter = LocusZoomPlotter(
|
|
@@ -163,27 +165,20 @@ fig = plotter.plot(
|
|
|
163
165
|
)
|
|
164
166
|
```
|
|
165
167
|
|
|
166
|
-
## Interactive Backends
|
|
168
|
+
## Interactive Backends (Coming Soon)
|
|
167
169
|
|
|
168
|
-
|
|
170
|
+
> **Note:** Interactive backends (plotly, bokeh) are planned but not yet fully integrated. Currently all plots use matplotlib.
|
|
169
171
|
|
|
170
172
|
```python
|
|
171
|
-
# Static publication-quality plot (default)
|
|
172
|
-
plotter = LocusZoomPlotter(species="
|
|
173
|
+
# Static publication-quality plot (default, currently only supported backend)
|
|
174
|
+
plotter = LocusZoomPlotter(species="canine", backend="matplotlib")
|
|
173
175
|
fig = plotter.plot(gwas_df, chrom=1, start=1000000, end=2000000)
|
|
174
176
|
fig.savefig("plot.png", dpi=150)
|
|
175
|
-
|
|
176
|
-
# Interactive with plotly (hover tooltips, zoom/pan)
|
|
177
|
-
plotter = LocusZoomPlotter(species="dog", backend="plotly")
|
|
178
|
-
fig = plotter.plot(gwas_df, chrom=1, start=1000000, end=2000000)
|
|
179
|
-
fig.write_html("plot.html")
|
|
180
|
-
|
|
181
|
-
# Interactive with bokeh (dashboard-friendly)
|
|
182
|
-
plotter = LocusZoomPlotter(species="dog", backend="bokeh")
|
|
183
|
-
fig = plotter.plot(gwas_df, chrom=1, start=1000000, end=2000000)
|
|
184
177
|
```
|
|
185
178
|
|
|
186
|
-
|
|
179
|
+
Future releases will support:
|
|
180
|
+
- **Plotly**: Interactive plots with hover tooltips, zoom/pan
|
|
181
|
+
- **Bokeh**: Dashboard-friendly interactive plots
|
|
187
182
|
|
|
188
183
|
## Stacked Plots
|
|
189
184
|
|
|
@@ -324,14 +319,14 @@ chr pos rate cM
|
|
|
324
319
|
|
|
325
320
|
## Reference Data
|
|
326
321
|
|
|
327
|
-
|
|
322
|
+
Canine recombination maps are downloaded from [Campbell et al. 2016](https://github.com/cflerin/dog_recombination) on first use.
|
|
328
323
|
|
|
329
324
|
To manually download:
|
|
330
325
|
|
|
331
326
|
```python
|
|
332
|
-
from pylocuszoom import
|
|
327
|
+
from pylocuszoom import download_canine_recombination_maps
|
|
333
328
|
|
|
334
|
-
|
|
329
|
+
download_canine_recombination_maps()
|
|
335
330
|
```
|
|
336
331
|
|
|
337
332
|
## Logging
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
pylocuszoom/__init__.py,sha256=f8h22YYL3JkDP5P_dJftu98qlJkXvaAeyto5kVc8bzU,3785
|
|
2
|
+
pylocuszoom/colors.py,sha256=XXTCmCFfHrOrSiP6b0V8Kis7Z1tyvGEKJpdv59QDVQ8,6610
|
|
3
|
+
pylocuszoom/eqtl.py,sha256=9lZJ8jT1WEj3won6D9B54xdqUvbRvxpOitf97NCUR28,6167
|
|
4
|
+
pylocuszoom/finemapping.py,sha256=IZEEF13m8xD2qfnTsqcv67BtPAvqC_FrXdGv1VG8BHk,6351
|
|
5
|
+
pylocuszoom/gene_track.py,sha256=ZYAWOUHOo9oieovl7VHGCB3j_HBbnr5wwtIwxozgRhE,10854
|
|
6
|
+
pylocuszoom/labels.py,sha256=Ams5WVZFNVT692BRiQ5wZcdbdNEAm5xtgRwmF5u0s_A,3492
|
|
7
|
+
pylocuszoom/ld.py,sha256=64xIulpDVvbMSryWUPoCQ99Odcjwf1wejpwVr_30MLU,6412
|
|
8
|
+
pylocuszoom/logging.py,sha256=nZHEkbnjp8zoyWj_S-Hy9UQvUYLoMoxyiOWRozBT2dg,4987
|
|
9
|
+
pylocuszoom/plotter.py,sha256=sPqK74B9-ldcKhrrWixyapIdQ4dVgFRERZfJw4ZNS5Y,37865
|
|
10
|
+
pylocuszoom/recombination.py,sha256=Q2tAft54nJWHlZt-vZje1r_5RP7D8_VUy5ab_deYXVw,13749
|
|
11
|
+
pylocuszoom/utils.py,sha256=fKNX9WSTbfHR1EpPYijt6ycNjXEjwzunQMHXAvHaK3s,5211
|
|
12
|
+
pylocuszoom/backends/__init__.py,sha256=7dlGvDoqMVK3fCtoMcI9zOP9qO0odQGPwfXhxnLfXfI,1196
|
|
13
|
+
pylocuszoom/backends/base.py,sha256=4EGT4_88y2jvhWm1zAal9v9yuaHhCLo7-rchcWmIK8c,8451
|
|
14
|
+
pylocuszoom/backends/bokeh_backend.py,sha256=V0yQi1lY96hjTjBXGJtLKGy1LFNii58kTAJiqu0LYPg,12900
|
|
15
|
+
pylocuszoom/backends/matplotlib_backend.py,sha256=yTTm9KG7e0ct-mvHk_tfJX6SOL97pABsJzs4Xn6H1zw,8010
|
|
16
|
+
pylocuszoom/backends/plotly_backend.py,sha256=2EDJZczqjZ5gItd3Fb4UaRYGj7SQy7Wgg5UIL8LJ9LM,14128
|
|
17
|
+
pylocuszoom/reference_data/__init__.py,sha256=qqHqAUt1jebGlCN3CjqW3Z-_coHVNo5K3a3bb9o83hA,109
|
|
18
|
+
pylocuszoom-0.2.0.dist-info/METADATA,sha256=tDPRbhg4r1NavMCH1e_VTzKY9qApsY97yyiEYh04S78,11723
|
|
19
|
+
pylocuszoom-0.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
20
|
+
pylocuszoom-0.2.0.dist-info/licenses/LICENSE.md,sha256=U2y_hv8RcN5lECA3uK88irU3ODUE1TDAPictcmnP0Q4,698
|
|
21
|
+
pylocuszoom-0.2.0.dist-info/RECORD,,
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
pylocuszoom/__init__.py,sha256=1TUI6bxbsPbNYrJR1-i_cffbh7mqYrXfFuUdF4r4sl8,3174
|
|
2
|
-
pylocuszoom/colors.py,sha256=VnQJEgC6uEBqjlu9mq16ijNn9gRwWHZEAqpu1E-KVug,2638
|
|
3
|
-
pylocuszoom/eqtl.py,sha256=GHOcSs2LRa4YHiKUm-ZNHQz5aR7z-5f8nRFpLvn8ezk,6154
|
|
4
|
-
pylocuszoom/gene_track.py,sha256=2U9JawzPfcjtQo_FhMMTw5juY8QQwRE6mTXy_JdChq4,10281
|
|
5
|
-
pylocuszoom/labels.py,sha256=PhplRqGa1G_4A1JZRdIa5ufnnkfLjpBoln-bs8IL7ok,3585
|
|
6
|
-
pylocuszoom/ld.py,sha256=Jwh_wi34IJMiaXBkNKPTL7S-YVEJXJfckJazSKN3ZBc,6282
|
|
7
|
-
pylocuszoom/logging.py,sha256=nZHEkbnjp8zoyWj_S-Hy9UQvUYLoMoxyiOWRozBT2dg,4987
|
|
8
|
-
pylocuszoom/plotter.py,sha256=B_5O5sXqln2oPUU2Nx8t8IRbqka7AzGfisH1fLorDpg,26991
|
|
9
|
-
pylocuszoom/recombination.py,sha256=qZHghHBnQLfaADo1PfGPGhRXuyaA5YZM8wI9FLnpfEk,13698
|
|
10
|
-
pylocuszoom/utils.py,sha256=1I4r9KOd8yje12L0Y7GiX2Adc7Qrefq5VqdHv83KM7g,5197
|
|
11
|
-
pylocuszoom/backends/__init__.py,sha256=DpPzFMe43FiZv3olsNTmb00il-sqdb6bKlDmFsQrnxY,1320
|
|
12
|
-
pylocuszoom/backends/base.py,sha256=CBubNWuP3qyovOXoseaf3a6CwsDQbujXy-HOTnHJYmE,8457
|
|
13
|
-
pylocuszoom/backends/bokeh_backend.py,sha256=4H_ay8jaWIVZtlyXGiPpm9sNmGMoF11U56ZjUqaL9YQ,12984
|
|
14
|
-
pylocuszoom/backends/matplotlib_backend.py,sha256=tThkVE-49nyKJYR5_qUPu2svk4LVR3HpP2Ac90FT3sw,7907
|
|
15
|
-
pylocuszoom/backends/plotly_backend.py,sha256=3-s3k93KgTzEKQJWcSb_NKGKzuKb3pLR3DEaUjOzJe8,14202
|
|
16
|
-
pylocuszoom/reference_data/__init__.py,sha256=qqHqAUt1jebGlCN3CjqW3Z-_coHVNo5K3a3bb9o83hA,109
|
|
17
|
-
pylocuszoom-0.1.0.dist-info/METADATA,sha256=k7iSnBOEKvDhzafDZjIjtuIOB5KefGy981kFyLXLEiM,11828
|
|
18
|
-
pylocuszoom-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
19
|
-
pylocuszoom-0.1.0.dist-info/licenses/LICENSE.md,sha256=U2y_hv8RcN5lECA3uK88irU3ODUE1TDAPictcmnP0Q4,698
|
|
20
|
-
pylocuszoom-0.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|