Skip to content

Commit 1102f77

Browse files
committed
Added save functions to API
1 parent d18fc20 commit 1102f77

File tree

9 files changed

+132
-12
lines changed

9 files changed

+132
-12
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,5 @@
3838
/gwplot/glfw_interface.cpp
3939
/gwplot/glfw_interface.cpython-310-darwin.so
4040
/examples/m21009_241011_231051.GRCh38.haplotagged.bam.bai
41+
/examples/output_online.png
42+
/examples/output_online.pdf

docs/docs/API.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,36 @@ Save the current raster image to a PNG file.
232232
gw.draw().save_png("visualization.png")
233233
```
234234

235+
### `save_pdf(path)`
236+
237+
Save the current raster image to a PDF file. Note draw() does not need to be called.
238+
239+
**Parameters:**
240+
- `path` (str): Path to save the PDF file
241+
242+
**Returns:**
243+
- `Gw`: Self for method chaining
244+
245+
**Example:**
246+
```python
247+
gw.save_pdf("visualization.pdf")
248+
```
249+
250+
### `save_svg(path)`
251+
252+
Save the current raster image to a SVG file. Note draw() does not need to be called.
253+
254+
**Parameters:**
255+
- `path` (str): Path to save the SVG file
256+
257+
**Returns:**
258+
- `Gw`: Self for method chaining
259+
260+
**Example:**
261+
```python
262+
gw.save_svg("visualization.svg")
263+
```
264+
235265
### `encode_as_png(compression_level=6)`
236266

237267
Encode the current canvas as PNG and return the binary data.

docs/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pip install gwplot
2626
- **Customizable themes and colors** for creating high-quality visualizations
2727
- **Multi-regions and data tracks** for comparative genomics
2828
- **Interactive mode** for dynamic exploration of genomic regions
29-
- **Flexible output formats** including PNG, JPEG, and NumPy arrays for further processing
29+
- **Flexible output formats** including PNG, PDF, SVG, JPEG, and NumPy arrays for further processing
3030
- **Built-in access** to common reference genomes
3131

3232
## Example Visualization
@@ -42,5 +42,5 @@ gw.add_bam("sample.bam")
4242
gw.add_region("chr1", 1000000, 1100000)
4343

4444
# Draw and save an image
45-
gw.draw().save_png("region.png")
45+
gw.save_pdf("region.pdf")
4646
```

examples/gwplot_matplotlib.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from gwplot import Gw
2+
import matplotlib.pyplot as plt
3+
import numpy as np
4+
plt.style.use('_mpl-gallery')
5+
6+
# Initialize with reference genome
7+
gw = Gw("hg19", theme="igv", canvas_width=2048, canvas_height=600)
8+
9+
# Add data sources
10+
gw.add_bam("https://github.com/kcleal/gw/releases/download/v1.0.0/demo1.bam")
11+
gw.add_region("chr8", 37047270, 37055161)
12+
gw.set_font_size(18)
13+
# Get the visualization as a NumPy array
14+
img_array = gw.draw().array()
15+
16+
# Create the figure with 2 subplots vertically stacked
17+
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8))
18+
19+
20+
# Display the gwplot visualization in the top subplot
21+
ax1.imshow(img_array)
22+
ax1.set_title('gwplot chr8:37047270-37055161')
23+
ax1.axis('off')
24+
25+
# Create the matplotlib plot in the bottom subplot
26+
x = np.linspace(0, 10, 100)
27+
y = 4 + 1 * np.sin(2 * x)
28+
x2 = np.linspace(0, 10, 25)
29+
y2 = 4 + 1 * np.sin(2 * x2)
30+
31+
ax2.plot(x2, y2 + 2.5, 'x', markeredgewidth=2)
32+
ax2.plot(x, y, linewidth=2.0)
33+
ax2.plot(x2, y2 - 2.5, 'o-', linewidth=2)
34+
35+
ax2.set(xlim=(0, 8), xticks=np.arange(1, 8),
36+
ylim=(0, 8), yticks=np.arange(1, 8))
37+
38+
# Adjust layout to prevent overlap
39+
plt.tight_layout()
40+
plt.show()

examples/save_png_local.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
from gwplot import Gw
22
import os
3-
root = os.path.abspath(os.path.dirname(__file__))
43

4+
root = os.path.abspath(os.path.dirname(__file__)).replace("/examples", "")
55

66
# Initialize with reference genome
7-
gw = Gw(root + "../tests/ref.fa")
7+
gw = Gw(root + "/tests/ref.fa")
88

99
# Add data sources
10-
gw.add_bam(root + "/../tests/small.bam")
10+
gw.add_bam(root + "/tests/small.bam")
1111

1212
# Set region to view
1313
gw.add_region("chr1", 1, 20000)

examples/save_png_online.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,4 @@
1111
gw.add_region("chr8", 37047270, 37055161)
1212

1313
# Render and save
14-
gw.draw()
15-
gw.save_png("output_online.png")
14+
gw.save_pdf("output_online.pdf")

gw

gwplot/interface.pxd

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,16 @@ cdef extern from "plot_manager.h" namespace "Manager" nogil:
129129

130130
void runDraw()
131131

132-
void rasterToPng(const char * path)
132+
void rasterToPng(const char* path)
133133

134134
vector[uint8_t]* encodeToPngVector(int compression_level)
135135

136136
vector[uint8_t]* encodeToJpegVector(int quality)
137137

138+
void saveToPdf(const char* path)
139+
140+
void saveToSvg(const char * path)
141+
138142
void keyPress(int key, int scancode, int action, int mods)
139143

140144
void windowResize(int x, int y)

gwplot/interface.pyx

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,6 +1632,45 @@ cdef class Gw:
16321632
self.thisptr.rasterToPng(c.c_str())
16331633
return self
16341634

1635+
def save_pdf(self, path):
1636+
"""
1637+
Saves a PDF file using the current configuration. Note calling draw() is
1638+
not needed beforehand.
1639+
1640+
Parameters
1641+
----------
1642+
path : str
1643+
Path to save the PDF file
1644+
1645+
Returns
1646+
-------
1647+
Gw
1648+
Self for method chaining
1649+
"""
1650+
cdef string c = path.encode("utf-8")
1651+
self.thisptr.saveToPdf(c.c_str())
1652+
return self
1653+
1654+
def save_svg(self, path):
1655+
"""
1656+
Saves an SVG file using the current configuration. Note calling draw() is
1657+
not needed beforehand.
1658+
1659+
Parameters
1660+
----------
1661+
path : str
1662+
Path to save the SVG file
1663+
1664+
Returns
1665+
-------
1666+
Gw
1667+
Self for method chaining
1668+
"""
1669+
cdef string c = path.encode("utf-8")
1670+
self.thisptr.saveToSvg(c.c_str())
1671+
return self
1672+
1673+
16351674
def draw_interactive(self, clear_buffer=False):
16361675
"""
16371676
Draw the visualization to the raster surface. Caches state for using with interactive functions.
@@ -1658,7 +1697,7 @@ cdef class Gw:
16581697

16591698
def draw(self):
16601699
"""
1661-
Draw the visualization to the raster surface without buffering.
1700+
Draw the visualization to the raster surface.
16621701
16631702
Creates the raster surface if it doesn't exist yet.
16641703
@@ -1670,7 +1709,10 @@ cdef class Gw:
16701709
if not self.raster_surface_created:
16711710
self.make_raster_surface()
16721711
self.thisptr.processed = False
1673-
self.thisptr.runDrawNoBuffer()
1712+
if self.thisptr.opts.link_op == 0:
1713+
self.thisptr.runDrawNoBuffer()
1714+
else:
1715+
self.thisptr.runDraw()
16741716
return self
16751717

16761718
def draw_image(self):
@@ -1685,7 +1727,10 @@ cdef class Gw:
16851727
if not self.raster_surface_created:
16861728
self.make_raster_surface()
16871729
self.thisptr.processed = False
1688-
self.thisptr.runDrawNoBuffer()
1730+
if self.thisptr.opts.link_op == 0:
1731+
self.thisptr.runDrawNoBuffer()
1732+
else:
1733+
self.thisptr.runDraw()
16891734
return Image.fromarray(self.array())
16901735

16911736
def view_region(self, chrom, start, end):

0 commit comments

Comments
 (0)