diff --git a/README.md b/README.md index 259aa76..4acb8c1 100644 --- a/README.md +++ b/README.md @@ -80,9 +80,9 @@ tnt run guoyi.run filename datatype weight 0/K cons resample prefix, - `apo.tre` is the apomorphic character mapping tree. -- `resample.tre` is the consensus tree with support. +- `resample.tre` is the consensus tree with support, which can be read by figtree after processing by tnt2figtree. -- `trees*.tre` contains he MPTs. +- `trees*.tre` contains he MPTs, which can be read by figtree after processing by tnt2figtree. - `resample/apo.log` contains the tree tags. @@ -100,58 +100,6 @@ tnt run guoyi.run filename datatype weight 0/K cons resample prefix, Cite this script is mandatory, list me (Guoyi Zhang) in your Acknowledgements is recommended. This script follows MIT License. -# TNT2WinClada +# Further information -``` -~|~|\ |~|~ ~) | |o._ |~| _ _| _ - | | \| | /_ \/\/ || ||_|(_|(_|(_| - -MIT, Guoyi Zhang, 2023 -``` - -## Function - -Convert TNT output tree file without tags and taxname, e.g. `winclada.tre` produced by TNT script, to WinClada acceptable format tree. - -## Compile - -### Linux & Unix - -``` -mkdir -p build && cd build -cmake .. -make && make install -``` - -### Windows - -``` -cl /EHsc tnt2winclada.cpp -``` - -## Usage - -``` -tnt2winclada -i ${input_file} -o ${output_file} -``` - -Interactive commands are also available. - -``` -tnt2winclada - -~|~|\ |~|~ ~) | |o._ |~| _ _| _ - | | \| | /_ \/\/ || ||_|(_|(_|(_| -TNT2WinClada -MIT, Guoyi Zhang, 2023 -please type help to see more commands - -tnt2winclada> help -help show interactive commands help -input input a TNT output tree from the specified file -output output a winclada accessible tree file -quit quit the program -exit exit the program - -tnt2winclada> -``` +To make tnt exported trees can be readable by WinClada (Nixon, 2021) and FigTree, please check tnt2winclada and tnt2figtree in this repository. diff --git a/src_tnt2figtree/CMakeLists.txt b/src_tnt2figtree/CMakeLists.txt new file mode 100644 index 0000000..cffa572 --- /dev/null +++ b/src_tnt2figtree/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.0) + +project(tnt2figtree) +SET( CMAKE_EXPORT_COMPILE_COMMANDS ON ) + +set(CMAKE_CXX_STANDARD 11) + +add_executable(tnt2figtree tnt2figtree.cpp) + +target_compile_options(tnt2figtree PRIVATE -Wall -Wextra -pedantic) + +install(TARGETS tnt2figtree DESTINATION /usr/bin) +install(FILES ../LICENSE DESTINATION /usr/share/licenses/tnt2figtree) +install(FILES README.md DESTINATION /usr/share/doc/tnt2figtree) diff --git a/src_tnt2figtree/README.md b/src_tnt2figtree/README.md new file mode 100644 index 0000000..6b93cf0 --- /dev/null +++ b/src_tnt2figtree/README.md @@ -0,0 +1,55 @@ +# TNT2FigTree + +``` +~|~|\ |~|~~)|~o(~|~|~._ _ _ + | | \| | /_|~| _| | | }_}_ + +MIT, Guoyi Zhang, 2024 +``` + +## Function + +Convert TNT output tree file with resample tags, e.g. `resample.tre` produced by TNT script `guoyi.run`, to complete nexus format tree. + +## Compile + +### Linux & Unix + +``` +mkdir -p build && cd build +cmake .. +make && make install +``` + +### Windows + +``` +cl /EHsc tnt2figtree.cpp +``` + +## Usage + +``` +tnt2figtree ${input_file} ${output_file} +``` + +Interactive commands are also available. + +``` +tnt2figtree + +~|~|\ |~|~~)|~o(~|~|~._ _ _ + | | \| | /_|~| _| | | }_}_ +TNT2FigTree +MIT, Guoyi Zhang, 2024 +please type help to see more commands + +tnt2figtree> help +help show interactive commands help +import import a TNT output nexus format tree by TNT export command +export export a nexus format tree file +quit quit the program +exit exit the program + +tnt2figree> +``` diff --git a/src_tnt2figtree/tnt2figtree.cpp b/src_tnt2figtree/tnt2figtree.cpp new file mode 100644 index 0000000..e7bd5a7 --- /dev/null +++ b/src_tnt2figtree/tnt2figtree.cpp @@ -0,0 +1,197 @@ +#include +#include +#include + +std::string remove_useless(std::string input_str1) +{ + std::string result_str1 = + std::regex_replace(input_str1, std::regex(" /*"), " "); + result_str1 = std::regex_replace(result_str1, std::regex("\\["), "{"); + result_str1 = std::regex_replace(result_str1, std::regex("\\]"), "}"); + return result_str1; +} + +std::string add_support(std::string input_str2) +{ + std::string result_str2 = ""; + size_t i = 0; + while (i < input_str2.length()) { + if (input_str2[i] == ')') { + result_str2 += input_str2[i]; + i++; + std::string support_str = ""; + while (i < input_str2.length() && + std::regex_match(std::string(1, input_str2[i]), + std::regex("[/0-9{}?]"))) { + support_str += input_str2[i]; + i++; + } + result_str2 += "[&support=\"" + support_str + "\"]"; + } + else { + result_str2 += input_str2[i]; + i++; + } + } + return result_str2; +} + +std::string add_blen(std::string input_str3) +{ + std::string result_str3 = ""; + int i = 0; + for (char c : input_str3) { + if (c == '(') { + i++; + result_str3 += c; + } + else if (c == ')') { + result_str3 += ":" + std::to_string(i) + c; + i--; + } + else if (c == ',') { + result_str3 += ":" + std::to_string(i) + c; + } + else { + result_str3 += c; + } + } + return result_str3; +} + +std::string remove_slash(std::string input_str4) +{ + std::string result_str4 = std::regex_replace( + input_str4, std::regex("\\[&support=\"[\\/\\s]*\"\\]"), ""); + return result_str4; +} + +std::vector get_lines(std::string filename) +{ + std::ifstream file(filename); + if (!file.is_open()) { + std::cout << "Failed to open the input file." << std::endl; + } + + std::vector lines; + std::string line; + while (std::getline(file, line)) { + lines.push_back(line); + } + file.close(); + return lines; +} + +std::vector process_line(std::vector lines, + size_t lineNum) +{ + std::string line = remove_useless(lines[lineNum]); + line = add_blen(line); + line = add_support(line); + + lines[lineNum] = remove_slash(line); + return lines; +} + +void write_lines(const std::vector& lines, + const std::string& filename) +{ + std::ofstream outfile(filename); + + if (!outfile.is_open()) { + std::cout << "Failed to open the output file." << std::endl; + } + + for (const std::string& line : lines) { + outfile << line << std::endl; + } + + outfile.close(); +} + +void interactive_commands(std::vector lines) +{ + std::string command, filename1, filename2; + std::cout + << "~|~|\\ |~|~~)|~o(~|~|~._ _ _\n | | \\| | /_|~| _| | | }_}_" + << std::endl; + std::cout << "TNT2FigTree\nMIT, Guoyi Zhang, 2024\nplease type help " + "to see more commands" + << std::endl; + while (true) { + std::cout << "tnt2figtree> "; + getline(std::cin, command); + if (command == "help") { + std::cout << "help\t\t\tshow interactive commands " + "help\nimport \timport a TNT " + "output nexus format tree by TNT export " + "command\nexport \texport a " + "nexus format tree file\nquit\t\t\tquit " + "the program\nexit\t\t\texit the program" + << std::endl; + } + else if (command.find("import ") == 0) { + std::stringstream ss(command.substr(7)); + ss >> filename1; + if (filename1.empty()) { + std::cout << "tnt2figtree> please specify a " + "filename." + << std::endl; + } + else { + lines = get_lines(filename1); + } + } + else if (command.find("export ") == 0) { + std::stringstream ss(command.substr(7)); + ss >> filename2; + if (filename2.empty()) { + std::cout << "tnt2figtree> please specify a " + "filename." + << std::endl; + } + else { + for (size_t i = 0; i < lines.size(); i++) { + if (lines[i][0] == '(') { + lines = process_line(lines, i); + } + } + write_lines(lines, filename2); + } + } + else if (command == "quit" || command == "exit") { + break; + } + else { + std::cout << "tnt2figtree> unrecognized command. Type " + "'help' for " + "a list of commands." + << std::endl; + } + } +} + +int main(int argc, char* argv[]) +{ + std::vector lines; + if (argc == 1) { + interactive_commands(lines); + return 0; + } + else if (argc == 3) { + lines = get_lines(argv[1]); + for (size_t i = 0; i < lines.size(); i++) { + if (lines[i][0] == '(') { + lines = process_line(lines, i); + } + } + write_lines(lines, argv[2]); + } + else { + std::cout << "Usage: " << argv[0] + << " " + << std::endl; + } + return 0; +} + diff --git a/src_tnt2winclada/CMakeLists.txt b/src_tnt2winclada/CMakeLists.txt new file mode 100644 index 0000000..86f2ed0 --- /dev/null +++ b/src_tnt2winclada/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.0) + +project(tnt2winclada) +SET( CMAKE_EXPORT_COMPILE_COMMANDS ON ) + +set(CMAKE_CXX_STANDARD 11) + +add_executable(tnt2winclada tnt2winclada.cpp) + +target_compile_options(tnt2winclada PRIVATE -Wall -Wextra -pedantic) + +install(TARGETS tnt2winclada DESTINATION /usr/bin) +install(FILES ../LICENSE DESTINATION /usr/share/licenses/tnt2winclada) +install(FILES README.md DESTINATION /usr/share/doc/tnt2winclada) diff --git a/src_tnt2winclada/README.md b/src_tnt2winclada/README.md new file mode 100644 index 0000000..d7fbf1d --- /dev/null +++ b/src_tnt2winclada/README.md @@ -0,0 +1,55 @@ +# TNT2WinClada + +``` +~|~|\ |~|~ ~) | |o._ |~| _ _| _ + | | \| | /_ \/\/ || ||_|(_|(_|(_| + +MIT, Guoyi Zhang, 2023 +``` + +## Function + +Convert TNT output tree file without tags and taxname, e.g. `winclada.tre` produced by TNT script `guoyi.run`, to WinClada acceptable format tree. + +## Compile + +### Linux & Unix + +``` +mkdir -p build && cd build +cmake .. +make && make install +``` + +### Windows + +``` +cl /EHsc tnt2winclada.cpp +``` + +## Usage + +``` +tnt2winclada -i ${input_file} -o ${output_file} +``` + +Interactive commands are also available. + +``` +tnt2winclada + +~|~|\ |~|~ ~) | |o._ |~| _ _| _ + | | \| | /_ \/\/ || ||_|(_|(_|(_| +TNT2WinClada +MIT, Guoyi Zhang, 2023 +please type help to see more commands + +tnt2winclada> help +help show interactive commands help +input input a TNT output tree from the specified file +output output a winclada accessible tree file +quit quit the program +exit exit the program + +tnt2winclada> +``` diff --git a/tnt2winclada.cpp b/src_tnt2winclada/tnt2winclada.cpp similarity index 100% rename from tnt2winclada.cpp rename to src_tnt2winclada/tnt2winclada.cpp