pylocuszoom 0.1.0__py3-none-any.whl → 0.3.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.
@@ -22,7 +22,7 @@ from .logging import logger
22
22
  RECOMB_COLOR = "#7FCDFF" # Light blue
23
23
 
24
24
  # Data sources by species
25
- DOG_RECOMB_URL = (
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 download_dog_recombination_maps(
180
+ def download_canine_recombination_maps(
181
181
  output_dir: Optional[str] = None,
182
182
  force: bool = False,
183
183
  ) -> Path:
184
- """Download dog recombination rate maps from Campbell et al. 2016.
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 dog recombination maps from GitHub...")
217
- logger.debug(f"Source: {DOG_RECOMB_URL}")
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(DOG_RECOMB_URL, tar_path)
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(DOG_RECOMB_URL, timeout=60)
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 = "dog",
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 dog, 1-18 for cat) or 'X'.
292
- species: Species name ('dog', 'cat').
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 = "dog",
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 ('dog', 'cat').
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 dog recombination maps are in CanFam3.1 coordinates.
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 == "dog" and build == "canfam4":
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("pyspark")
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.1.0
3
+ Version: 0.3.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
@@ -19,6 +19,7 @@ Classifier: Programming Language :: Python :: 3.12
19
19
  Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
20
20
  Classifier: Topic :: Scientific/Engineering :: Visualization
21
21
  Requires-Python: >=3.10
22
+ Requires-Dist: adjusttext>=0.8
22
23
  Requires-Dist: bokeh>=3.8.2
23
24
  Requires-Dist: kaleido>=0.2.0
24
25
  Requires-Dist: loguru>=0.7.0
@@ -28,14 +29,11 @@ Requires-Dist: pandas>=1.4.0
28
29
  Requires-Dist: plotly>=5.0.0
29
30
  Requires-Dist: pyliftover>=0.4
30
31
  Provides-Extra: all
31
- Requires-Dist: adjusttext>=0.8; extra == 'all'
32
32
  Requires-Dist: pyspark>=3.0.0; extra == 'all'
33
33
  Provides-Extra: dev
34
34
  Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
35
35
  Requires-Dist: pytest>=7.0.0; extra == 'dev'
36
36
  Requires-Dist: ruff>=0.1.0; extra == 'dev'
37
- Provides-Extra: labels
38
- Requires-Dist: adjusttext>=0.8; extra == 'labels'
39
37
  Provides-Extra: spark
40
38
  Requires-Dist: pyspark>=3.0.0; extra == 'spark'
41
39
  Description-Content-Type: text/markdown
@@ -71,16 +69,24 @@ Inspired by [LocusZoom](http://locuszoom.org/) and [locuszoomr](https://github.c
71
69
  - **eQTL overlay**: Expression QTL data as separate panel
72
70
  - **PySpark support**: Handles large-scale genomics DataFrames
73
71
 
72
+ ![Example regional association plot](examples/regional_plot.png)
73
+
74
74
  ## Installation
75
75
 
76
+ ```bash
77
+ pip install pylocuszoom
78
+ ```
79
+
80
+ Or with uv:
81
+
76
82
  ```bash
77
83
  uv add pylocuszoom
78
84
  ```
79
85
 
80
- Or with pip:
86
+ Or with conda (Bioconda):
81
87
 
82
88
  ```bash
83
- pip install pylocuszoom
89
+ conda install -c bioconda pylocuszoom
84
90
  ```
85
91
 
86
92
  ## Quick Start
@@ -88,8 +94,8 @@ pip install pylocuszoom
88
94
  ```python
89
95
  from pylocuszoom import LocusZoomPlotter
90
96
 
91
- # Initialize plotter (loads reference data for dog)
92
- plotter = LocusZoomPlotter(species="dog")
97
+ # Initialize plotter (loads reference data for canine)
98
+ plotter = LocusZoomPlotter(species="canine")
93
99
 
94
100
  # Create regional plot
95
101
  fig = plotter.plot(
@@ -109,7 +115,7 @@ fig.savefig("regional_plot.png", dpi=150)
109
115
  from pylocuszoom import LocusZoomPlotter
110
116
 
111
117
  plotter = LocusZoomPlotter(
112
- species="dog", # or "cat", or None for custom
118
+ species="canine", # or "feline", or None for custom
113
119
  plink_path="/path/to/plink", # Optional, auto-detects if on PATH
114
120
  )
115
121
 
@@ -134,10 +140,10 @@ fig = plotter.plot(
134
140
 
135
141
  ## Genome Builds
136
142
 
137
- The default genome build for dog is CanFam3.1. For CanFam4 data:
143
+ The default genome build for canine is CanFam3.1. For CanFam4 data:
138
144
 
139
145
  ```python
140
- plotter = LocusZoomPlotter(species="dog", genome_build="canfam4")
146
+ plotter = LocusZoomPlotter(species="canine", genome_build="canfam4")
141
147
  ```
142
148
 
143
149
  Recombination maps are automatically lifted over from CanFam3.1 to CanFam4 coordinates using the UCSC liftOver chain file.
@@ -145,8 +151,8 @@ Recombination maps are automatically lifted over from CanFam3.1 to CanFam4 coord
145
151
  ## Using with Other Species
146
152
 
147
153
  ```python
148
- # Cat (LD and gene tracks, user provides recombination data)
149
- plotter = LocusZoomPlotter(species="cat")
154
+ # Feline (LD and gene tracks, user provides recombination data)
155
+ plotter = LocusZoomPlotter(species="feline")
150
156
 
151
157
  # Custom species (provide all reference data)
152
158
  plotter = LocusZoomPlotter(
@@ -163,27 +169,30 @@ fig = plotter.plot(
163
169
  )
164
170
  ```
165
171
 
166
- ## Interactive Backends
172
+ ## Backends
167
173
 
168
- Choose between static (matplotlib) and interactive (plotly, bokeh) outputs:
174
+ pyLocusZoom supports multiple rendering backends:
169
175
 
170
176
  ```python
171
177
  # Static publication-quality plot (default)
172
- plotter = LocusZoomPlotter(species="dog", backend="matplotlib")
173
- fig = plotter.plot(gwas_df, chrom=1, start=1000000, end=2000000)
178
+ fig = plotter.plot(gwas_df, chrom=1, start=1000000, end=2000000, backend="matplotlib")
174
179
  fig.savefig("plot.png", dpi=150)
175
180
 
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)
181
+ # Interactive Plotly (hover tooltips, pan/zoom)
182
+ fig = plotter.plot(gwas_df, chrom=1, start=1000000, end=2000000, backend="plotly")
179
183
  fig.write_html("plot.html")
180
184
 
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)
185
+ # Interactive Bokeh (dashboard-ready)
186
+ fig = plotter.plot(gwas_df, chrom=1, start=1000000, end=2000000, backend="bokeh")
184
187
  ```
185
188
 
186
- Interactive plots show SNP details (RS ID, p-value, R²) on hover.
189
+ | Backend | Output | Best For |
190
+ |---------|--------|----------|
191
+ | `matplotlib` | Static PNG/PDF/SVG | Publications, presentations |
192
+ | `plotly` | Interactive HTML | Web reports, data exploration |
193
+ | `bokeh` | Interactive HTML | Dashboards, web apps |
194
+
195
+ > **Note:** All backends support gene track, recombination overlay, and LD legend. SNP labels (auto-positioned with adjustText) are matplotlib-only.
187
196
 
188
197
  ## Stacked Plots
189
198
 
@@ -324,14 +333,14 @@ chr pos rate cM
324
333
 
325
334
  ## Reference Data
326
335
 
327
- Dog recombination maps are downloaded from [Campbell et al. 2016](https://github.com/cflerin/dog_recombination) on first use.
336
+ Canine recombination maps are downloaded from [Campbell et al. 2016](https://github.com/cflerin/dog_recombination) on first use.
328
337
 
329
338
  To manually download:
330
339
 
331
340
  ```python
332
- from pylocuszoom import download_dog_recombination_maps
341
+ from pylocuszoom import download_canine_recombination_maps
333
342
 
334
- download_dog_recombination_maps()
343
+ download_canine_recombination_maps()
335
344
  ```
336
345
 
337
346
  ## 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=PJ4HJYeCaHZecUmADCEGQxKd9HhhjrdIA1H5LQsUmLI,6332
5
+ pylocuszoom/gene_track.py,sha256=CbKqIIl-3VpqIS0NWQ7p-VazhrgbF0-XDkkvoWx_2jI,18665
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=7wEN0b3emb0SM7gYn8bSjXBGNt7npw3y3y5AEC-Ha2k,43660
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=YEYMtaqPRTJQI-TPqK62-XPN6WvjVwqP6e6ydULK6H0,8523
14
+ pylocuszoom/backends/bokeh_backend.py,sha256=oOXTOhSx-tNgBzgtYfYvGUgNmuUP2vhCbtEBOZ5YZ18,18496
15
+ pylocuszoom/backends/matplotlib_backend.py,sha256=TIKaT7x0X3QKYUB5076XlG6RC0zbi0hcm3LSU7LGnmw,8521
16
+ pylocuszoom/backends/plotly_backend.py,sha256=ucQLmcz6WAdEvII5n3_rdHffZv5-a8FOp8nBGBng-hk,22222
17
+ pylocuszoom/reference_data/__init__.py,sha256=qqHqAUt1jebGlCN3CjqW3Z-_coHVNo5K3a3bb9o83hA,109
18
+ pylocuszoom-0.3.0.dist-info/METADATA,sha256=P-JbXF9KxFzixMAYKQalKO4F4TwOqxDZD0B0uciyy_c,12068
19
+ pylocuszoom-0.3.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
20
+ pylocuszoom-0.3.0.dist-info/licenses/LICENSE.md,sha256=U2y_hv8RcN5lECA3uK88irU3ODUE1TDAPictcmnP0Q4,698
21
+ pylocuszoom-0.3.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,,