1- use bio:: alignment:: {
2- pairwise:: { Aligner , Scoring } ,
3- Alignment , AlignmentOperation ,
4- } ;
1+ use bio:: alignment:: pairwise:: { Aligner , Scoring } ;
52use clap:: Parser ;
6- use colored:: Colorize ;
73use rustyms:: { MonoIsotopic , Peptide } ;
8- use std:: fmt:: Write ;
4+
5+ mod render;
6+ mod stats;
7+
8+ use render:: * ;
99
1010#[ derive( Parser , Debug ) ]
1111#[ command( author, version, about, long_about) ]
@@ -41,8 +41,7 @@ struct Args {
4141
4242fn main ( ) {
4343 let args = Args :: parse ( ) ;
44- if args. global & args. semi_global || args. global && args. local || args. semi_global && args. local
45- {
44+ if args. global as u8 + args. semi_global as u8 + args. local as u8 > 1 {
4645 panic ! ( "Cannot have multiple alignment types at the same time" )
4746 }
4847 if args. mass {
@@ -56,7 +55,11 @@ fn main() {
5655 rustyms:: align:: Type :: Global
5756 } ;
5857 let alignment = rustyms:: align:: align :: < MonoIsotopic > ( a, b, rustyms:: align:: BLOSUM62 , ty) ;
59- println ! ( "{:?}\n \n {}" , alignment, alignment. summary( ) ) ;
58+ show_mass_alignment (
59+ & alignment,
60+ ty == rustyms:: align:: Type :: Global ,
61+ args. line_width ,
62+ ) ;
6063 } else if args. x . contains ( ',' ) {
6164 for ( x, y) in args. x . split ( ',' ) . zip ( args. y . split ( ',' ) ) {
6265 align ( & args, x. as_bytes ( ) , y. as_bytes ( ) ) ;
@@ -79,121 +82,6 @@ fn align(args: &Args, x: &[u8], y: &[u8]) {
7982 show_alignment ( & alignment, x, y, args. semi_global , args. line_width ) ;
8083}
8184
82- fn show_alignment (
83- alignment : & Alignment ,
84- sequence_x : & [ u8 ] ,
85- sequence_y : & [ u8 ] ,
86- semi_global : bool ,
87- line_width : usize ,
88- ) {
89- let ( identical, similar, gaps, length) = score_stats ( alignment, sequence_x, sequence_y) ;
90-
91- println ! (
92- "Identity: {} {}, Similarity: {} {}, Gaps: {:} {}, Score: {}{}\n " ,
93- format!( "{:.3}" , identical as f64 / length as f64 ) . blue( ) ,
94- format!( "({}/{})" , identical, length) . dimmed( ) ,
95- format!( "{:.3}" , similar as f64 / length as f64 ) . cyan( ) ,
96- format!( "({}/{})" , similar, length) . dimmed( ) ,
97- format!( "{:.3}" , gaps as f64 / length as f64 ) . green( ) ,
98- format!( "({}/{})" , gaps, length) . dimmed( ) ,
99- format!( "{}" , alignment. score) . yellow( ) ,
100- if semi_global {
101- format!( "\n CIGAR: {}" , alignment. cigar( false ) )
102- } else {
103- String :: new( )
104- }
105- ) ;
106-
107- macro_rules! line {
108- ( $lines: ident, $x: expr, $y: expr, $c: expr, $colour: ident) => {
109- write!( & mut $lines. 0 , "{}" , $x. $colour( ) ) . unwrap( ) ;
110- write!( & mut $lines. 1 , "{}" , $y. $colour( ) ) . unwrap( ) ;
111- write!( & mut $lines. 2 , "{}" , $c. $colour( ) ) . unwrap( ) ;
112- } ;
113- }
114-
115- let mut lines = ( String :: new ( ) , String :: new ( ) , String :: new ( ) ) ;
116- let mut numbers = String :: new ( ) ;
117- let mut x = alignment. xstart ;
118- let mut y = alignment. ystart ;
119- // Similar: · Gap: ◯ Identical: ∘ ⏺ ∘◯◦ ⚪ ⚫ ⬤ ⭘ 🞄 ∘ ○ ● ◦ ◯ ⴰ ⨉⨯+-
120- for ( index, step) in alignment. operations . iter ( ) . enumerate ( ) {
121- match step {
122- AlignmentOperation :: Del => {
123- line ! (
124- lines,
125- "-" ,
126- String :: from_utf8_lossy( & [ sequence_y[ y] ] ) ,
127- "+" ,
128- yellow
129- ) ;
130- y += 1 ;
131- }
132- AlignmentOperation :: Ins => {
133- line ! (
134- lines,
135- String :: from_utf8_lossy( & [ sequence_x[ x] ] ) ,
136- "-" ,
137- "+" ,
138- yellow
139- ) ;
140- x += 1 ;
141- }
142- AlignmentOperation :: Subst => {
143- if SIMILAR . contains ( & ( sequence_x[ x] , sequence_y[ y] ) ) {
144- line ! (
145- lines,
146- String :: from_utf8_lossy( & [ sequence_x[ x] ] ) ,
147- String :: from_utf8_lossy( & [ sequence_y[ y] ] ) ,
148- "-" ,
149- green
150- ) ;
151- } else {
152- line ! (
153- lines,
154- String :: from_utf8_lossy( & [ sequence_x[ x] ] ) ,
155- String :: from_utf8_lossy( & [ sequence_y[ y] ] ) ,
156- "⨯" ,
157- red
158- ) ;
159- }
160- x += 1 ;
161- y += 1 ;
162- }
163- AlignmentOperation :: Match => {
164- line ! (
165- lines,
166- String :: from_utf8_lossy( & [ sequence_x[ x] ] ) ,
167- String :: from_utf8_lossy( & [ sequence_y[ y] ] ) ,
168- " " ,
169- normal
170- ) ;
171- x += 1 ;
172- y += 1 ;
173- }
174- AlignmentOperation :: Xclip ( _) => todo ! ( ) ,
175- AlignmentOperation :: Yclip ( _) => todo ! ( ) ,
176- }
177- write ! ( & mut numbers, " " ) . unwrap ( ) ;
178- if ( index + 1 ) % 10 == 0 {
179- numbers. truncate ( numbers. len ( ) - number_length ( index + 1 ) ) ;
180- write ! ( & mut numbers, "{}" , index + 1 ) . unwrap ( ) ;
181- }
182- if ( index + 1 ) % line_width == 0 {
183- println ! ( "{}" , numbers. dimmed( ) ) ;
184- println ! ( "{}" , lines. 0 ) ;
185- println ! ( "{}" , lines. 1 ) ;
186- println ! ( "{}" , lines. 2 ) ;
187- lines = ( String :: new ( ) , String :: new ( ) , String :: new ( ) ) ;
188- numbers = String :: new ( ) ;
189- }
190- }
191- println ! ( "{}" , numbers. dimmed( ) ) ;
192- println ! ( "{}" , lines. 0 ) ;
193- println ! ( "{}" , lines. 1 ) ;
194- println ! ( "{}" , lines. 2 ) ;
195- }
196-
19785pub fn get_blosum62 ( gap_open : i32 , gap_extend : i32 ) -> Scoring < impl Fn ( u8 , u8 ) -> i32 > {
19886 const TRANSLATION_TABLE : & [ usize ] = include ! ( "translation_table.txt" ) ;
19987 const BLOSUM62 : & [ & [ i32 ] ] = include ! ( "blosum62.txt" ) ;
@@ -210,69 +98,3 @@ pub fn get_blosum62(gap_open: i32, gap_extend: i32) -> Scoring<impl Fn(u8, u8) -
21098 } ;
21199 Scoring :: new ( gap_open, gap_extend, match_fn)
212100}
213-
214- pub fn score_stats (
215- alignment : & Alignment ,
216- sequence_x : & [ u8 ] ,
217- sequence_y : & [ u8 ] ,
218- ) -> ( usize , usize , usize , usize ) {
219- let x_len = sequence_x. len ( ) ;
220- let y_len = sequence_y. len ( ) ;
221- let mut x = alignment. xstart ;
222- let mut y = alignment. ystart ;
223- let mut identical = 0 ;
224- let mut similar = 0 ;
225- let mut gaps = 0 ;
226- for step in & alignment. operations {
227- match step {
228- AlignmentOperation :: Del => {
229- y += 1 ;
230- gaps += 1 ;
231- }
232- AlignmentOperation :: Ins => {
233- x += 1 ;
234- gaps += 1 ;
235- }
236- AlignmentOperation :: Subst => {
237- if SIMILAR . contains ( & ( sequence_x[ x] , sequence_y[ y] ) ) {
238- similar += 1 ;
239- }
240- x += 1 ;
241- y += 1 ;
242- }
243- AlignmentOperation :: Match => {
244- x += 1 ;
245- y += 1 ;
246- identical += 1 ;
247- }
248- AlignmentOperation :: Xclip ( _) => todo ! ( ) ,
249- AlignmentOperation :: Yclip ( _) => todo ! ( ) ,
250- }
251- }
252- debug_assert ! ( x == alignment. xend) ;
253- debug_assert ! ( y == alignment. yend) ;
254- ( identical, similar + identical, gaps, ( x_len) . max ( y_len) )
255- }
256-
257- fn number_length ( i : usize ) -> usize {
258- if i == 0 {
259- 1
260- } else {
261- i. ilog10 ( ) as usize + 1
262- }
263- }
264-
265- const SIMILAR : & [ ( u8 , u8 ) ] = & [ ( b'I' , b'L' ) , ( b'L' , b'I' ) , ( b'D' , b'N' ) , ( b'N' , b'D' ) ] ;
266-
267- #[ test]
268- fn number_length_test ( ) {
269- assert_eq ! ( number_length( 0 ) , 1 ) ;
270- assert_eq ! ( number_length( 1 ) , 1 ) ;
271- assert_eq ! ( number_length( 9 ) , 1 ) ;
272- assert_eq ! ( number_length( 10 ) , 2 ) ;
273- assert_eq ! ( number_length( 11 ) , 2 ) ;
274- assert_eq ! ( number_length( 99 ) , 2 ) ;
275- assert_eq ! ( number_length( 100 ) , 3 ) ;
276- assert_eq ! ( number_length( 1000 ) , 4 ) ;
277- assert_eq ! ( number_length( 10000 ) , 5 ) ;
278- }
0 commit comments