1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use clap::*;
use intspan::*;
use std::io::BufRead;
// Create clap subcommand arguments
pub fn make_subcommand() -> Command {
Command::new("circos")
.about("Convert links to circos links or highlights")
.after_help(
r###"
* It's assumed that all ranges in input files are valid
"###,
)
.arg(
Arg::new("infiles")
.required(true)
.num_args(1..)
.index(1)
.help("Set the input files to use"),
)
.arg(
Arg::new("highlight")
.long("highlight")
.action(ArgAction::SetTrue)
.help("Create highlights instead of links"),
)
.arg(
Arg::new("outfile")
.long("outfile")
.short('o')
.num_args(1)
.default_value("stdout")
.help("Output filename. [stdout] for screen"),
)
}
// command implementation
pub fn execute(args: &ArgMatches) -> anyhow::Result<()> {
//----------------------------
// Loading
//----------------------------
let mut writer = writer(args.get_one::<String>("outfile").unwrap());
let is_highlight = args.get_flag("highlight");
let mut colors = (1..=12)
.map(|n| format!("paired-12-qual-{}", n))
.collect::<Vec<String>>();
colors.reverse();
let mut color_idx = 0;
for infile in args.get_many::<String>("infiles").unwrap() {
let reader = reader(infile);
for line in reader.lines().map_while(Result::ok) {
let parts: Vec<&str> = line.split('\t').collect();
if is_highlight {
for part in parts {
let range = Range::from_str(part);
if !range.is_valid() {
continue;
}
//----------------------------
// Output
//----------------------------
writer.write_all(
format!(
"{} {} {} fill_color={}\n",
range.chr(),
range.start(),
range.end(),
colors[color_idx]
)
.as_ref(),
)?;
}
// rotate color
color_idx += 1;
if color_idx > 11 {
color_idx = 0;
}
} else {
let count = parts.len();
// 2-combinations of parts forms a pair
for i in 0..count {
'PAIR: for j in i + 1..count {
let mut fields: Vec<String> = vec![];
for idx in &[i, j] {
let range = Range::from_str(parts[*idx]);
if !range.is_valid() {
continue 'PAIR;
}
fields.push(range.chr().to_string());
if range.strand() == "-" {
fields.push(range.end().to_string());
fields.push(range.start().to_string());
} else {
fields.push(range.start().to_string());
fields.push(range.end().to_string());
}
}
//----------------------------
// Output
//----------------------------
writer.write_all(format!("{}\n", fields.join(" ")).as_ref())?;
}
}
}
} // end of line
}
Ok(())
}