source: trunk/EDIT4/ED4_dots.cxx

Last change on this file was 19206, checked in by westram, 2 years ago
File size: 10.3 KB
Line 
1// ================================================================ //
2//                                                                  //
3//   File      : ED4_dots.cxx                                       //
4//   Purpose   : Insert dots where bases may be missing             //
5//                                                                  //
6//   Coded by Ralf Westram (coder@reallysoft.de) in December 2008   //
7//   Institute of Microbiology (Technical University Munich)        //
8//   http://www.arb-home.de/                                        //
9//                                                                  //
10// ================================================================ //
11
12#include "ed4_dots.hxx"
13#include "ed4_class.hxx"
14
15#include <awt_sel_boxes.hxx>
16#include <aw_awar.hxx>
17#include <aw_msg.hxx>
18#include <aw_root.hxx>
19#include <arbdbt.h>
20#include <cctype>
21#include <awt_config_manager.hxx>
22
23using namespace std;
24
25#define AWAR_DOT_BASE      "dotmiss/"
26#define AWAR_DOT_SAI       AWAR_DOT_BASE "sainame" // selected SAI
27#define AWAR_DOT_SAI_CHARS AWAR_DOT_BASE "chars"   // handle columns where SAI contains one of these chars
28#define AWAR_DOT_MARKED    AWAR_DOT_BASE "marked"  // handle marked only?
29
30struct dot_insert_stat {
31    size_t  pos_count;
32    size_t *position;           // contains 'pos_count' positions, where dots get inserted if sequence contains '-'
33
34    bool marked_only;
35
36    // statistics:
37    size_t dots_inserted;
38    size_t already_there;
39    size_t sequences_checked;
40};
41
42static ARB_ERROR dot_sequence_by_consensus(ED4_base *base, dot_insert_stat *statPtr) {
43    ARB_ERROR error = NULp;
44
45    if (base->is_sequence_info_terminal()) {
46        ED4_sequence_info_terminal *seq_term = base->to_sequence_info_terminal();
47        if (seq_term) {
48            GBDATA *gb_ali = seq_term->data();
49            if (gb_ali) {
50                GBDATA           *gb_species = GB_get_grandfather(gb_ali);
51                bool              marked     = GB_read_flag(gb_species);
52                dot_insert_stat&  stat       = *statPtr;
53
54                if (marked || !stat.marked_only) {
55                    char *sequence = GB_read_string(gb_ali);
56
57                    if (!sequence) {
58                        GB_ERROR err = GB_await_error();
59                        error        = GBS_global_string("No sequence found for '%s'\n(Reason: %s)",
60                                                         GBT_get_name_or_description(gb_species), err);
61                    }
62                    else {
63                        size_t length            = GB_read_string_count(gb_ali);
64                        size_t old_dots_inserted = stat.dots_inserted;
65
66                        for (size_t p = 0; p<stat.pos_count; p++) {
67                            size_t pos = stat.position[p];
68
69                            if (pos<length) {
70                                switch (sequence[pos]) {
71                                    case '-':
72                                        sequence[pos] = '.';
73                                        stat.dots_inserted++;
74                                        break;
75
76                                    case '.':
77                                        stat.already_there++;
78                                        break;
79
80                                    default:
81                                        break;
82                                }
83                            }
84                        }
85
86                        if (stat.dots_inserted > old_dots_inserted) { // did sequence change?
87                            error = GB_write_string(gb_ali, sequence);
88                        }
89
90                        free(sequence);
91                        stat.sequences_checked++;
92                    }
93                }
94            }
95        }
96    }
97
98    return error;
99}
100
101static void dot_missing_bases(AW_window *aww) {
102    ED4_MostRecentWinContext context;
103
104    ED4_cursor *cursor = &current_cursor();
105    ARB_ERROR   error  = NULp;
106
107    if (!cursor->in_consensus_terminal()) {
108        error = "No consensus selected";
109    }
110    else {
111        AW_root *aw_root = aww->get_root();
112
113        dot_insert_stat stat;
114        stat.dots_inserted     = 0;
115        stat.already_there     = 0;
116        stat.position          = NULp;
117        stat.sequences_checked = 0;
118        stat.marked_only       = aw_root->awar(AWAR_DOT_MARKED)->read_int();
119
120        ED4_group_manager *group_manager = cursor->owner_of_cursor->get_parent(LEV_GROUP)->to_group_manager();
121        {
122            // build list of positions where consensus contains upper case characters:
123            char *consensus = group_manager->build_consensus_string();
124            for (int pass = 1; pass <= 2; pass++) {
125                stat.pos_count = 0;
126                for (int pos = 0; consensus[pos]; pos++) {
127                    if (isupper(consensus[pos])) {
128                        if (pass == 2) stat.position[stat.pos_count] = pos;
129                        stat.pos_count++;
130                    }
131                }
132
133                if (pass == 1) ARB_alloc(stat.position, stat.pos_count);
134            }
135            free(consensus);
136        }
137
138        GBDATA *gb_main = ED4_ROOT->get_gb_main();
139        if (!stat.pos_count) {
140            error = "No consensus column contains upper case characters";
141        }
142        else {
143            // if SAI is selected, reduce list of affected positions
144            char   *sai     = NULp;
145            size_t  sai_len = -1;
146            {
147                GB_transaction  ta(gb_main);
148                char           *sai_name = aw_root->awar(AWAR_DOT_SAI)->read_string();
149
150                if (sai_name && sai_name[0]) {
151                    GBDATA *gb_sai     = GBT_expect_SAI(gb_main, sai_name);
152                    if (!gb_sai) error = GB_await_error();
153                    else {
154                        GBDATA *gb_ali = GBT_find_sequence(gb_sai, ED4_ROOT->get_alignment_name());
155                        if (!gb_ali) {
156                            error = GBS_global_string("SAI '%s' has no data in '%s'", sai_name, ED4_ROOT->get_alignment_name());
157                        }
158                        else {
159                            sai     = GB_read_string(gb_ali); // @@@ NOT_ALL_SAI_HAVE_DATA
160                            sai_len = GB_read_string_count(gb_ali);
161                        }
162                    }
163                }
164                free(sai_name);
165                error = ta.close(error);
166            }
167
168            if (sai) { // SAI is selected
169                if (!error) {
170                    char *sai_chars = aw_root->awar(AWAR_DOT_SAI_CHARS)->read_string();
171                    if (sai_chars[0] == 0) error = "No SAI characters given -> no column selectable";
172                    else {
173                        size_t k = 0;
174                        size_t p;
175                        for (p = 0; p<stat.pos_count && stat.position[p]<sai_len; p++) {
176                            size_t  pos = stat.position[p];
177                            if (strchr(sai_chars, sai[pos])) { // SAI contains one of the 'sai_chars'
178                                stat.position[k++] = pos; // use current position
179                            }
180                        }
181                        stat.pos_count = k;
182
183                        if (!stat.pos_count) error = "SAI selects other columns than consensus. Nothing to do.";
184                    }
185                    free(sai_chars);
186                }
187                free(sai);
188            }
189        }
190
191        if (!error) {
192            e4_assert(stat.pos_count);
193            GB_transaction ta(gb_main);
194            error = group_manager->route_down_hierarchy(makeED4_route_cb(dot_sequence_by_consensus, &stat));
195
196            if (stat.sequences_checked == 0 && !error) {
197                error = GBS_global_string("Group contains no %ssequences", stat.marked_only ? "marked " : "");
198            }
199
200            if (!error) {
201                const char *present = "";
202                if (stat.already_there) {
203                    present = GBS_global_string("Dots already present: %zu  ", stat.already_there);
204                }
205
206                const char *changed = stat.dots_inserted
207                    ? GBS_global_string("Gaps changed into dots: %zu", stat.dots_inserted)
208                    : "No gaps were changed into dots.";
209
210                aw_message(GBS_global_string("%s%s", present, changed));
211            }
212
213            error = ta.close(error);
214        }
215    }
216
217    aw_message_if(error);
218}
219
220void ED4_create_dot_missing_bases_awars(AW_root *aw_root, AW_default aw_def) {
221    aw_root->awar_int(AWAR_DOT_MARKED, 0, aw_def);
222    aw_root->awar_string(AWAR_DOT_SAI, "", aw_def);
223    aw_root->awar_string(AWAR_DOT_SAI_CHARS, "", aw_def);
224}
225
226static AWT_config_mapping_def dotbases_config_mapping[] = {
227    { AWAR_DOT_MARKED,    "marked" },
228    { AWAR_DOT_SAI,       "sai" },
229    { AWAR_DOT_SAI_CHARS, "saichars" },
230
231    { NULp, NULp }
232};
233
234void ED4_popup_dot_missing_bases_window(AW_window *editor_window) {
235    AW_root                 *aw_root = editor_window->get_root();
236    static AW_window_simple *aws     = NULp;
237
238    ED4_LocalWinContext uses(editor_window);
239
240    if (!aws) {
241        aws = new AW_window_simple;
242
243        aws->init(aw_root, "DOT_MISS_BASES", "Dot potentially missing bases");
244        aws->load_xfig("edit4/missbase.fig");
245
246        aws->button_length(10);
247
248        aws->at("close");
249        aws->callback(AW_POPDOWN);
250        aws->create_button("CLOSE", "CLOSE", "C");
251
252        aws->at("help");
253        aws->callback(makeHelpCallback("missbase.hlp"));
254        aws->create_button("HELP", "HELP", "H");
255
256        aws->at("marked");
257        aws->label("Marked species only");
258        aws->create_toggle(AWAR_DOT_MARKED);
259
260        aws->at("SAI");
261        aws->button_length(30);
262        awt_create_SAI_selection_button(ED4_ROOT->get_gb_main(), aws, AWAR_DOT_SAI);
263
264        aws->at("SAI_chars");
265        aws->label("contains one of");
266        aws->create_input_field(AWAR_DOT_SAI_CHARS, 20);
267
268        aws->button_length(10);
269
270        aws->at("cons_def");
271        aws->label("Change definition of");
272        aws->callback(ED4_create_consensus_definition_window);
273        aws->create_button("CONS_DEF", "Consensus", "C");
274
275        aws->at("go");
276        aws->callback(dot_missing_bases);
277        aws->create_button("GO", "GO", "G");
278
279        aws->at("config");
280        AWT_insert_config_manager(aws, AW_ROOT_DEFAULT, "dotbases", dotbases_config_mapping);
281    }
282
283    e4_assert(aws);
284
285    aws->activate();
286}
287
Note: See TracBrowser for help on using the repository browser.