Skip to content

Commit

Permalink
Merge pull request #62 from anergictcell/release/0.10.0
Browse files Browse the repository at this point in the history
Release/0.10.0
  • Loading branch information
anergictcell authored Jun 11, 2024
2 parents d831c08 + e1b193e commit 88d16d0
Show file tree
Hide file tree
Showing 17 changed files with 1,029 additions and 252 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,28 @@ All notable changes to this project will be documented in this file.

## Unreleased

## [0.10.0]

### Feature

- Add Orphante diseases (`OrphaDisease`) to Ontology
- Filter gene and disease annotations in subontology based on association with phenotypes
- Add binary version 3
- Add new example ontology

### Documentation

- Change orders of methods in `Ontology` to clean up the documentation.

### Refactor

- Improve the OBO parser with better error handling
- [**breaking**] Add `Disease` trait that is needed to work with `OmimDisease` and `OrphaDisease`
- Update example ontology
- Update unit- and doctests to align with updated example ontology

## [0.9.0] - 2024-03-27

## [0.9.1] - 2024-03-30

### Bugfix

Expand Down
3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "hpo"
version = "0.9.1"
version = "0.10.0"
edition = "2021"
authors = ["Jonas Marcello <jonas.marcello@esbme.com>"]
description = "Human Phenotype Ontology Similarity"
Expand All @@ -15,7 +15,6 @@ categories = ["science", "data-structures", "parser-implementations"]
[dependencies]
thiserror = "1.0"
aquamarine = "0" # used in Docs
statrs = "0.16.0"
tracing = "0.1"
smallvec = "1"

Expand Down
16 changes: 10 additions & 6 deletions examples/compare_ontologies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fn ontology(path_arg: &str) -> Ontology {
}
}

fn ontology2(path_arg: &str) -> Ontology {
fn ontology_transitive(path_arg: &str) -> Ontology {
let path = Path::new(path_arg);

match path.is_file() {
Expand Down Expand Up @@ -226,17 +226,21 @@ fn print_replacement_diff(replacements: Option<(Option<HpoTermId>, Option<HpoTer
fn main() {
let mut args = std::env::args();

if args.len() != 3 {
if args.len() < 2 {
println!("Compare two Ontologies to each other and print the differences\n\n");
println!("Usage:\ncompare_ontologies </PATH/TO/ONTOLOGY> </PATH/TO/OTHER-ONTOLOGY>");
println!("Usage:\ncompare_ontologies </PATH/TO/ONTOLOGY> [</PATH/TO/OTHER-ONTOLOGY>]");
println!("e.g.:\ncompare_ontologies tests/ontology.hpo tests/ontology_v2.hpo:\n");
println!("Alternatively compare transitive vs non-transitive:\ncompare_ontologies tests/ontology.hpo\n");
process::exit(1)
}
let arg_old = args.nth(1).unwrap();
let arg_new = args.next().unwrap();

let lhs = ontology(&arg_old);
let rhs = ontology2(&arg_new);

let rhs = if let Some(arg_new) = args.next() {
ontology(&arg_new)
} else {
ontology_transitive(&arg_old)
};

let diffs = lhs.compare(&rhs);

Expand Down
15 changes: 10 additions & 5 deletions src/annotations/gene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,6 @@ impl Gene {
&self.name
}

/// Connect another [HPO term](`crate::HpoTerm`) to the gene
pub fn add_term<I: Into<HpoTermId>>(&mut self, term_id: I) -> bool {
self.hpos.insert(term_id)
}

/// The set of connected HPO terms
pub fn hpo_terms(&self) -> &HpoGroup {
&self.hpos
Expand Down Expand Up @@ -193,6 +188,16 @@ impl Gene {
pub fn to_hpo_set<'a>(&self, ontology: &'a Ontology) -> HpoSet<'a> {
HpoSet::new(ontology, self.hpos.clone())
}

/// Connect another [HPO term](`crate::HpoTerm`) to the gene
///
/// # Note
///
/// This method does **not** add the [`Gene`] to the [HPO term](`crate::HpoTerm`).
/// Clients should not use this method, unless they are creating their own Ontology.
pub fn add_term<I: Into<HpoTermId>>(&mut self, term_id: I) -> bool {
self.hpos.insert(term_id)
}
}

impl PartialEq for Gene {
Expand Down
81 changes: 74 additions & 7 deletions src/annotations/omim_disease.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ use std::hash::Hash;
use crate::annotations::disease::DiseaseIterator;
use crate::annotations::{AnnotationId, Disease};
use crate::term::HpoGroup;
use crate::HpoError;
use crate::HpoTermId;
use crate::{HpoError, HpoSet, HpoTermId, Ontology};

/// A set of OMIM diseases
///
Expand Down Expand Up @@ -93,15 +92,83 @@ impl Disease for OmimDisease {
&self.name
}

/// Connect another [HPO term](`crate::HpoTerm`) to the disease
fn add_term<I: Into<HpoTermId>>(&mut self, term_id: I) -> bool {
self.hpos.insert(term_id)
}

/// The set of connected HPO terms
fn hpo_terms(&self) -> &HpoGroup {
&self.hpos
}

/// Returns a binary representation of the `OmimDisease`
///
/// The binary layout is defined as:
///
/// | Byte offset | Number of bytes | Description |
/// | --- | --- | --- |
/// | 0 | 4 | The total length of the binary data blob as big-endian `u32` |
/// | 4 | 4 | The `OmimDiseaseId` as big-endian `u32` |
/// | 8 | 4 | The length of the `OmimDisease` Name as big-endian `u32` |
/// | 12 | n | The `OmimDisease` name as u8 vector |
/// | 12 + n | 4 | The number of associated HPO terms as big-endian `u32` |
/// | 16 + n | x * 4 | The [`HpoTermId`]s of the associated terms, each encoded as big-endian `u32` |
///
/// # Examples
///
/// ```
/// use hpo::annotations::{Disease, OmimDisease};
///
/// let mut disease = OmimDisease::new(123.into(), "FooBar");
/// let bytes = disease.as_bytes();
///
/// assert_eq!(bytes.len(), 4 + 4 + 4 + 6 + 4);
/// assert_eq!(bytes[4..8], [0u8, 0u8, 0u8, 123u8]); // ID of disease => 123
/// assert_eq!(bytes[8..12], [0u8, 0u8, 0u8, 6u8]); // Length of Name => 6
/// ```
fn as_bytes(&self) -> Vec<u8> {
fn usize_to_u32(n: usize) -> u32 {
n.try_into().expect("unable to convert {n} to u32")
}
let name = self.name().as_bytes();
let name_length = name.len();
let size = 4 + 4 + 4 + name_length + 4 + self.hpos.len() * 4;

let mut res = Vec::new();

// 4 bytes for total length
res.append(&mut usize_to_u32(size).to_be_bytes().to_vec());

// 4 bytes for OMIM Disease-ID
res.append(&mut self.id.to_be_bytes().to_vec());

// 4 bytes for Length of OMIM Disease Name
res.append(&mut usize_to_u32(name_length).to_be_bytes().to_vec());

// OMIM Disease name (n bytes)
for c in name {
res.push(*c);
}

// 4 bytes for number of HPO terms
res.append(&mut usize_to_u32(self.hpos.len()).to_be_bytes().to_vec());

// HPO terms
res.append(&mut self.hpos.as_bytes());

res
}

/// Returns an [`HpoSet`] from the `OmimDisease`
fn to_hpo_set<'a>(&self, ontology: &'a Ontology) -> HpoSet<'a> {
HpoSet::new(ontology, self.hpos.clone())
}

/// Connect another [HPO term](`crate::HpoTerm`) to the disease
///
/// # Note
///
/// This method does **not** add the [`OmimDisease`] to the [HPO term](`crate::HpoTerm`).
/// Clients should not use this method, unless they are creating their own Ontology.
fn add_term<I: Into<HpoTermId>>(&mut self, term_id: I) -> bool {
self.hpos.insert(term_id)
}
}

impl PartialEq for OmimDisease {
Expand Down
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub mod utils;
pub use ontology::comparison;
pub use ontology::Ontology;
pub use set::HpoSet;
#[doc(inline)]
pub use term::{HpoTerm, HpoTermId};

const DEFAULT_NUM_PARENTS: usize = 10;
Expand Down Expand Up @@ -59,6 +60,9 @@ pub enum HpoError {
/// Failed to convert an integer to a float
#[error("cannot convert int to float")]
TryFromIntError(#[from] std::num::TryFromIntError),
/// Failed to parse a line of input data from the JAX obo
#[error("invalid input data: {0}")]
InvalidInput(String),
}

impl From<ParseIntError> for HpoError {
Expand Down
Loading

0 comments on commit 88d16d0

Please sign in to comment.