-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
32e65e8
commit 881174c
Showing
31 changed files
with
1,855 additions
and
1,686 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
[package] | ||
name = "pipeplot" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
resvg = "0.36" | ||
usvg = "0.36" | ||
tiny-skia = "0.11" | ||
svg2pdf = "0.9" | ||
tempfile = "3" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
use crate::{pdf, png, svg, PipePlot}; | ||
use std::path::{Path, PathBuf}; | ||
use tempfile::NamedTempFile; | ||
|
||
pub fn generate(plot: &PipePlot, path: &PathBuf) -> Result<(), String> { | ||
let extension = Path::new(path) | ||
.extension() | ||
.and_then(|ext| ext.to_str()) | ||
.ok_or_else(|| format!("Failed to get extension from path: {path:?}"))?; | ||
let file_type = FileType::from_extension(extension) | ||
.ok_or_else(|| format!("Unsupported file extension: {extension:?}"))?; | ||
|
||
let temp_dir = PathBuf::from(&path); | ||
let temp_dir = temp_dir | ||
.parent() | ||
.ok_or_else(|| format!("Invalid path: {path:?}"))?; | ||
let svg_temp_path = NamedTempFile::new_in(temp_dir) | ||
.map_err(|e| format!("Failed to create temporary file: {e}"))? | ||
.into_temp_path(); | ||
|
||
svg::generate(plot, &svg_temp_path.to_path_buf()); | ||
match file_type { | ||
FileType::Svg => svg_temp_path.persist(path).map_err(|e| e.to_string())?, | ||
FileType::Png => png::render(&svg_temp_path.to_path_buf(), path)?, | ||
FileType::Pdf => pdf::render(&svg_temp_path.to_path_buf(), path)?, | ||
} | ||
Ok(()) | ||
} | ||
|
||
#[derive(Debug, PartialEq)] | ||
enum FileType { | ||
Svg, | ||
Png, | ||
Pdf, | ||
} | ||
|
||
impl FileType { | ||
fn from_extension(extension: &str) -> Option<Self> { | ||
match extension.to_lowercase().as_str() { | ||
"svg" => Some(FileType::Svg), | ||
"png" => Some(FileType::Png), | ||
"pdf" => Some(FileType::Pdf), | ||
_ => None, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/*! | ||
This crate provides functionality to generate the so-called "pipe plots" | ||
consisting of stacked horizontal pipes (bars). Each pipe consists of segments of | ||
specified width, shape, and color. Pipe plots can be annotated with scales, | ||
labels, and legends. The crate supports rendering of pipe plots as SVG, PNG, and | ||
PDF images. | ||
Pipe plots are useful for representing pileups of sequenced reads. | ||
*/ | ||
|
||
mod image; | ||
mod pdf; | ||
mod pipeplot; | ||
mod png; | ||
mod svg; | ||
|
||
pub use image::generate as generate_image; | ||
pub use pipeplot::{Band, Color, Legend, Pipe, PipePlot, Seg, Shape}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,14 @@ | ||
use std::path::PathBuf; | ||
use usvg::{TreeParsing, TreeTextToPath}; | ||
|
||
pub fn render(svg_path: &str, pdf_path: &str) { | ||
let svg = std::fs::read_to_string(svg_path).unwrap(); | ||
pub fn render(svg_path: &PathBuf, pdf_path: &PathBuf) -> Result<(), String> { | ||
let svg = std::fs::read_to_string(svg_path).map_err(|e| e.to_string())?; | ||
let options = usvg::Options::default(); | ||
let mut tree = usvg::Tree::from_str(&svg, &options).expect("Error parsing SVG"); | ||
let mut db = usvg::fontdb::Database::new(); | ||
db.load_system_fonts(); | ||
tree.convert_text(&db); | ||
let pdf = svg2pdf::convert_tree(&tree, svg2pdf::Options::default()); | ||
std::fs::write(pdf_path, pdf).unwrap(); | ||
std::fs::write(pdf_path, pdf).map_err(|e| e.to_string())?; | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
#[derive(Debug, PartialEq)] | ||
pub enum Shape { | ||
Rect, | ||
HLine, | ||
VLine, | ||
None, | ||
Tick(Option<u32>), | ||
} | ||
|
||
pub type Color = String; | ||
|
||
#[derive(Debug, PartialEq)] | ||
pub struct Seg { | ||
pub width: u32, | ||
pub color: Color, | ||
pub shape: Shape, | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct Band { | ||
pub pos: u32, // Position relative to pipe's start | ||
pub width: u32, | ||
pub color: Color, | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct Pipe { | ||
pub xpos: u32, | ||
pub ypos: u32, | ||
pub height: u32, | ||
pub segs: Vec<Seg>, | ||
pub bands: Vec<Band>, | ||
pub outline: bool, | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct Legend { | ||
pub xpos: u32, | ||
pub ypos: u32, | ||
pub height: u32, | ||
pub labels: Vec<(String, String)>, | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct PipePlot { | ||
pub pipes: Vec<Pipe>, | ||
pub legend: Legend, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,18 @@ | ||
use std::path::PathBuf; | ||
use usvg::{TreeParsing, TreeTextToPath}; | ||
|
||
pub fn render(svg_path: &str, png_path: &str) { | ||
let svg = std::fs::read(svg_path).unwrap(); | ||
pub fn render(svg_path: &PathBuf, png_path: &PathBuf) -> Result<(), String> { | ||
let svg = std::fs::read(svg_path).map_err(|e| e.to_string())?; | ||
let options = usvg::Options::default(); | ||
let mut tree = usvg::Tree::from_data(&svg, &options).unwrap(); | ||
let mut tree = usvg::Tree::from_data(&svg, &options).map_err(|e| e.to_string())?; | ||
let mut db = usvg::fontdb::Database::new(); | ||
db.load_system_fonts(); | ||
tree.convert_text(&db); | ||
let pixmap_size = tree.size.to_int_size(); | ||
let mut pixmap = tiny_skia::Pixmap::new(pixmap_size.width(), pixmap_size.height()).unwrap(); | ||
let mut pixmap = tiny_skia::Pixmap::new(pixmap_size.width(), pixmap_size.height()) | ||
.ok_or("Unable to init image".to_string())?; | ||
let tree = resvg::Tree::from_usvg(&tree); | ||
tree.render(resvg::usvg::Transform::identity(), &mut pixmap.as_mut()); | ||
pixmap.save_png(png_path).unwrap(); | ||
pixmap.save_png(png_path).map_err(|e| e.to_string())?; | ||
Ok(()) | ||
} |
Oops, something went wrong.