Skip to content

Commit 881174c

Browse files
Update to version 1.3.0
1 parent 32e65e8 commit 881174c

31 files changed

+1855
-1686
lines changed

Cargo.lock

Lines changed: 306 additions & 233 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
[package]
22
name = "trgt"
3-
version = "1.2.0"
3+
version = "1.3.0"
44
edition = "2021"
55
build = "build.rs"
66

7+
[workspace]
8+
members = ["crates/pipeplot"]
9+
710
[build-dependencies]
811
vergen = { version = "8.2", features = ["git", "gitcl"] }
912

@@ -20,11 +23,8 @@ kodama = "0.3"
2023
rand = "0.8"
2124
once_cell = "1.18"
2225
flate2 = "1.0"
23-
resvg = "0.36"
24-
usvg = "0.36"
25-
tiny-skia = "0.11"
26-
svg2pdf = "0.9"
27-
tempfile = "3"
2826
rayon = "1.10"
2927
crossbeam-channel = "0.5"
30-
semver = "1.0"
28+
pipeplot = { path = "crates/pipeplot" }
29+
semver = "1.0"
30+
tempfile = "3"

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,12 @@ tandem repeats at genome scale. 2024](https://www.nature.com/articles/s41587-023
136136
- Merging now skips and logs problematic loci by default. Use the `--quit-on-errors` flag to terminate on errors. Statistics are logged post-merge, including counts of failed and skipped TRs.
137137
- `trgt validate`
138138
- Always outputs statistics directly to stdout and stderr instead of logging them.
139-
- Bug fix:
139+
- Bug fix:
140140
- Resolved issue with handling bgzip-compressed BED files.
141+
- 1.3.0
142+
- Plotting code has been refactored as we prepare to revamp repeat visualizations
143+
- The maximum number of reads per allele to plot can now be specified by `--max-allele-reads`
144+
- bugfix: repeat identifiers are now permitted to contain commas
141145

142146
### DISCLAIMER
143147

crates/pipeplot/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "pipeplot"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
resvg = "0.36"
10+
usvg = "0.36"
11+
tiny-skia = "0.11"
12+
svg2pdf = "0.9"
13+
tempfile = "3"

crates/pipeplot/src/image.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use crate::{pdf, png, svg, PipePlot};
2+
use std::path::{Path, PathBuf};
3+
use tempfile::NamedTempFile;
4+
5+
pub fn generate(plot: &PipePlot, path: &PathBuf) -> Result<(), String> {
6+
let extension = Path::new(path)
7+
.extension()
8+
.and_then(|ext| ext.to_str())
9+
.ok_or_else(|| format!("Failed to get extension from path: {path:?}"))?;
10+
let file_type = FileType::from_extension(extension)
11+
.ok_or_else(|| format!("Unsupported file extension: {extension:?}"))?;
12+
13+
let temp_dir = PathBuf::from(&path);
14+
let temp_dir = temp_dir
15+
.parent()
16+
.ok_or_else(|| format!("Invalid path: {path:?}"))?;
17+
let svg_temp_path = NamedTempFile::new_in(temp_dir)
18+
.map_err(|e| format!("Failed to create temporary file: {e}"))?
19+
.into_temp_path();
20+
21+
svg::generate(plot, &svg_temp_path.to_path_buf());
22+
match file_type {
23+
FileType::Svg => svg_temp_path.persist(path).map_err(|e| e.to_string())?,
24+
FileType::Png => png::render(&svg_temp_path.to_path_buf(), path)?,
25+
FileType::Pdf => pdf::render(&svg_temp_path.to_path_buf(), path)?,
26+
}
27+
Ok(())
28+
}
29+
30+
#[derive(Debug, PartialEq)]
31+
enum FileType {
32+
Svg,
33+
Png,
34+
Pdf,
35+
}
36+
37+
impl FileType {
38+
fn from_extension(extension: &str) -> Option<Self> {
39+
match extension.to_lowercase().as_str() {
40+
"svg" => Some(FileType::Svg),
41+
"png" => Some(FileType::Png),
42+
"pdf" => Some(FileType::Pdf),
43+
_ => None,
44+
}
45+
}
46+
}

crates/pipeplot/src/lib.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*!
2+
This crate provides functionality to generate the so-called "pipe plots"
3+
consisting of stacked horizontal pipes (bars). Each pipe consists of segments of
4+
specified width, shape, and color. Pipe plots can be annotated with scales,
5+
labels, and legends. The crate supports rendering of pipe plots as SVG, PNG, and
6+
PDF images.
7+
8+
Pipe plots are useful for representing pileups of sequenced reads.
9+
*/
10+
11+
mod image;
12+
mod pdf;
13+
mod pipeplot;
14+
mod png;
15+
mod svg;
16+
17+
pub use image::generate as generate_image;
18+
pub use pipeplot::{Band, Color, Legend, Pipe, PipePlot, Seg, Shape};
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1+
use std::path::PathBuf;
12
use usvg::{TreeParsing, TreeTextToPath};
23

3-
pub fn render(svg_path: &str, pdf_path: &str) {
4-
let svg = std::fs::read_to_string(svg_path).unwrap();
4+
pub fn render(svg_path: &PathBuf, pdf_path: &PathBuf) -> Result<(), String> {
5+
let svg = std::fs::read_to_string(svg_path).map_err(|e| e.to_string())?;
56
let options = usvg::Options::default();
67
let mut tree = usvg::Tree::from_str(&svg, &options).expect("Error parsing SVG");
78
let mut db = usvg::fontdb::Database::new();
89
db.load_system_fonts();
910
tree.convert_text(&db);
1011
let pdf = svg2pdf::convert_tree(&tree, svg2pdf::Options::default());
11-
std::fs::write(pdf_path, pdf).unwrap();
12+
std::fs::write(pdf_path, pdf).map_err(|e| e.to_string())?;
13+
Ok(())
1214
}

crates/pipeplot/src/pipeplot.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#[derive(Debug, PartialEq)]
2+
pub enum Shape {
3+
Rect,
4+
HLine,
5+
VLine,
6+
None,
7+
Tick(Option<u32>),
8+
}
9+
10+
pub type Color = String;
11+
12+
#[derive(Debug, PartialEq)]
13+
pub struct Seg {
14+
pub width: u32,
15+
pub color: Color,
16+
pub shape: Shape,
17+
}
18+
19+
#[derive(Debug)]
20+
pub struct Band {
21+
pub pos: u32, // Position relative to pipe's start
22+
pub width: u32,
23+
pub color: Color,
24+
}
25+
26+
#[derive(Debug)]
27+
pub struct Pipe {
28+
pub xpos: u32,
29+
pub ypos: u32,
30+
pub height: u32,
31+
pub segs: Vec<Seg>,
32+
pub bands: Vec<Band>,
33+
pub outline: bool,
34+
}
35+
36+
#[derive(Debug)]
37+
pub struct Legend {
38+
pub xpos: u32,
39+
pub ypos: u32,
40+
pub height: u32,
41+
pub labels: Vec<(String, String)>,
42+
}
43+
44+
#[derive(Debug)]
45+
pub struct PipePlot {
46+
pub pipes: Vec<Pipe>,
47+
pub legend: Legend,
48+
}
Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1+
use std::path::PathBuf;
12
use usvg::{TreeParsing, TreeTextToPath};
23

3-
pub fn render(svg_path: &str, png_path: &str) {
4-
let svg = std::fs::read(svg_path).unwrap();
4+
pub fn render(svg_path: &PathBuf, png_path: &PathBuf) -> Result<(), String> {
5+
let svg = std::fs::read(svg_path).map_err(|e| e.to_string())?;
56
let options = usvg::Options::default();
6-
let mut tree = usvg::Tree::from_data(&svg, &options).unwrap();
7+
let mut tree = usvg::Tree::from_data(&svg, &options).map_err(|e| e.to_string())?;
78
let mut db = usvg::fontdb::Database::new();
89
db.load_system_fonts();
910
tree.convert_text(&db);
1011
let pixmap_size = tree.size.to_int_size();
11-
let mut pixmap = tiny_skia::Pixmap::new(pixmap_size.width(), pixmap_size.height()).unwrap();
12+
let mut pixmap = tiny_skia::Pixmap::new(pixmap_size.width(), pixmap_size.height())
13+
.ok_or("Unable to init image".to_string())?;
1214
let tree = resvg::Tree::from_usvg(&tree);
1315
tree.render(resvg::usvg::Transform::identity(), &mut pixmap.as_mut());
14-
pixmap.save_png(png_path).unwrap();
16+
pixmap.save_png(png_path).map_err(|e| e.to_string())?;
17+
Ok(())
1518
}

0 commit comments

Comments
 (0)