source: branches/species/NTREE/NT_branchAnalysis.cxx

Last change on this file was 19613, checked in by westram, 2 months ago
  • reintegrates 'lib' into 'trunk'
    • replace dynamic library AWT by several static libraries: APP, ARB_SPEC, MASKS, CANVAS, MAPKEY, GUI_TK
    • now also check wrong library dependencies for untested units (only4me)
  • adds: log:branches/lib@19578:19612
File size: 12.1 KB
Line 
1// ============================================================== //
2//                                                                //
3//   File      : NT_branchAnalysis.cxx                            //
4//   Purpose   :                                                  //
5//                                                                //
6//   Coded by Ralf Westram (coder@reallysoft.de) in August 2012   //
7//   Institute of Microbiology (Technical University Munich)      //
8//   http://www.arb-home.de/                                      //
9//                                                                //
10// ============================================================== //
11
12#include "NT_local.h"
13#include <TreeCallbacks.hxx>
14#include <aw_awar.hxx>
15#include <aw_msg.hxx>
16#include <aw_root.hxx>
17#include <config_manager.hxx>
18
19#define AWAR_BRANCH_ANALYSIS     "branch_analysis"
20#define AWAR_BRANCH_ANALYSIS_TMP "tmp/" AWAR_BRANCH_ANALYSIS
21
22#define AWAR_BA_MIN_REL_DIFF AWAR_BRANCH_ANALYSIS "/min_rel_diff"
23#define AWAR_BA_MIN_ABS_DIFF AWAR_BRANCH_ANALYSIS "/min_abs_diff"
24#define AWAR_BA_MIN_DEPTH    AWAR_BRANCH_ANALYSIS "/min_depth"
25#define AWAR_BA_MIN_ROOTDIST AWAR_BRANCH_ANALYSIS "/min_rootdist"
26#define AWAR_BA_DEGENERATION AWAR_BRANCH_ANALYSIS "/degeneration"
27
28#define AWAR_BA_AUTOMARK_FORMAT AWAR_BRANCH_ANALYSIS_TMP "/auto_%s"
29
30// AISC_MKPT_PROMOTE:class TREE_canvas;
31
32class BranchWindow : virtual Noncopyable {
33    TREE_canvas      *ntw;
34    char             *suffix;
35    AW_awar          *awar_info;
36    AW_window_simple *aws;
37
38    static char *get_suffix(TREE_canvas *ntw) {
39        // suffix depends on canvas
40        return GBS_global_string_copy("_%i", ntw->get_index());
41    }
42
43    const char *local_awar_name (const char *prefix, const char *name) { return GBS_global_string("%s%s/%s", prefix, suffix, name); }
44
45    void create_awars(AW_root *aw_root);
46    void create_window(AW_root *aw_root);
47
48    const char *automark_awarname() const { return GBS_global_string(AWAR_BA_AUTOMARK_FORMAT, suffix); }
49
50public:
51    BranchWindow(AW_root *aw_root, TREE_canvas *ntw_)
52        : ntw(ntw_),
53          suffix(get_suffix(ntw))
54    {
55        create_awars(aw_root);
56        create_window(aw_root);
57    }
58
59    ~BranchWindow() {
60        free(suffix);
61    }
62
63    AW_window *get_window() const { return aws; }
64
65private:
66    AW_root *get_awroot() const { return get_window()->get_root(); }
67    TREE_canvas *get_canvas() const { return ntw; }
68    AP_tree *get_tree() const { return AWT_TREE(ntw)->get_root_node(); }
69    GBDATA *get_gbmain() const { return get_canvas()->gb_main; }
70    AW_awar *awar(const char *name) { return get_awroot()->awar(name); }
71
72    void postmark_action() const {
73        AWT_auto_refresh allowed_on(get_canvas());
74        get_canvas()->request_structure_update();
75    }
76
77    bool have_tree() {
78        if (get_tree()) return true;
79        set_info("No tree selected");
80        return false;
81    }
82
83    static void adapt_intawar_max(AW_awar *awar, int val, int extra) { // @@@ move to AW_awar?
84        // adapt maximum defined for int-awar (according to encountered maximum 'val' + a bit 'extra' range)
85        nt_assert(awar->get_type() == AW_INT);
86
87        int max = awar->get_max();
88        if (max<val || ((val*2) < max && awar->get_min()<val)) {
89            awar->set_max(val+extra);
90        }
91    }
92    static void adapt_floatawar_max(AW_awar *awar, double val, double extra) { // @@@ move to AW_awar?
93        // adapt maximum defined for float-awar (according to encountered maximum 'val' + a bit 'extra' range)
94        nt_assert(awar->get_type() == AW_FLOAT);
95
96        double max = awar->get_max();
97        if (max<val || ((val*2) < max && awar->get_min()<val)) {
98            awar->set_max(val+extra);
99        }
100    }
101
102public:
103    void set_info(const char *msg) const { awar_info->write_string(msg); }
104    void unmark_all() const { NT_mark_all_cb(NULp, get_canvas(), 0); }
105
106    AW_awar *automark_awar() const { return get_awroot()->awar(automark_awarname()); }
107    bool has_automark_set() const { return automark_awar()->read_int(); }
108
109    void markDegeneratedBranches() {
110        if (have_tree()) {
111            GB_transaction ta(get_gbmain());
112
113            AW_awar *awar_degen          = awar(AWAR_BA_DEGENERATION);
114            double   degeneration_factor = awar_degen->read_float();
115
116            unmark_all();
117
118            double found_max_degeneration = get_tree()->mark_degenerated_branches(degeneration_factor);
119            set_info(GBS_global_string("Maximum degeneration = %.2f", found_max_degeneration));
120            adapt_floatawar_max(awar_degen, found_max_degeneration, 1.0);
121
122            postmark_action();
123        }
124    }
125    void markDeepLeafs() {
126        if (have_tree()) {
127            GB_transaction ta(get_gbmain());
128
129            AW_awar *awar_min_depth    = awar(AWAR_BA_MIN_DEPTH);
130            AW_awar *awar_min_rootdist = awar(AWAR_BA_MIN_ROOTDIST);
131            int      min_depth         = awar_min_depth->read_int();
132            double   min_rootdist      = awar_min_rootdist->read_float();
133            int      found_max_depth;
134            double   found_max_rootdist;
135
136            unmark_all();
137            set_info(get_tree()->mark_deep_leafs(min_depth, min_rootdist, found_max_depth, found_max_rootdist));
138            adapt_intawar_max(awar_min_depth, found_max_depth, 1);
139            adapt_floatawar_max(awar_min_rootdist, found_max_rootdist, 0.1);
140            postmark_action();
141        }
142    }
143    void markLongBranches() {
144        if (have_tree()) {
145            GB_transaction ta(get_gbmain());
146
147            AW_awar *awar_abs_diff = awar(AWAR_BA_MIN_ABS_DIFF);
148            double   min_rel_diff  = awar(AWAR_BA_MIN_REL_DIFF)->read_float()/100.0;
149            double   min_abs_diff  = awar_abs_diff->read_float();
150            double   found_max_abs_diff;
151
152            unmark_all();
153            set_info(get_tree()->mark_long_branches(min_rel_diff, min_abs_diff, found_max_abs_diff));
154            adapt_floatawar_max(awar_abs_diff, found_max_abs_diff, 0.1);
155            postmark_action();
156        }
157    }
158
159    void analyseDistances() {
160        if (have_tree()) {
161            GB_transaction ta(get_gbmain());
162            set_info(get_tree()->analyse_distances());
163        }
164    }
165};
166
167static BranchWindow *existingBranchWindow[MAX_NT_WINDOWS] = { MAX_NT_WINDOWS_NULLINIT };
168
169// --------------------------------------------------------------------------------
170
171static void mark_long_branches_cb       (AW_window*, BranchWindow *bw) { bw->markLongBranches(); }
172static void mark_deep_leafs_cb          (AW_window*, BranchWindow *bw) { bw->markDeepLeafs(); }
173static void mark_degenerated_branches_cb(AW_window*, BranchWindow *bw) { bw->markDegeneratedBranches(); }
174static void unmark_branches_cb          (AW_window*, BranchWindow *bw) { bw->unmark_all(); }
175static void distance_analysis_cb        (AW_window*, BranchWindow *bw) { bw->analyseDistances(); }
176
177static void tree_changed_cb             (AW_root*,   BranchWindow *bw) { bw->set_info("<tree has changed>"); }
178
179static BranchWindow *findAutomarkingBranchWindow() {
180    for (int w = 0; w<MAX_NT_WINDOWS; ++w) {
181        BranchWindow *bw = existingBranchWindow[w];
182        if (bw && bw->has_automark_set()) {
183            return bw;
184        }
185    }
186    return NULp;
187}
188
189static void mark_long_branches_automark_cb() {
190    BranchWindow *bw = findAutomarkingBranchWindow();
191    if (bw) bw->markLongBranches();
192}
193static void mark_deep_leafs_automark_cb() {
194    BranchWindow *bw = findAutomarkingBranchWindow();
195    if (bw) bw->markDeepLeafs();
196}
197static void mark_degenerated_branches_automark_cb() {
198    BranchWindow *bw = findAutomarkingBranchWindow();
199    if (bw) bw->markDegeneratedBranches();
200}
201
202static void automark_changed_cb(AW_root *, BranchWindow *bw) {
203    static bool avoid_recursion = false;
204    if (!avoid_recursion) {
205        AW_awar *awar_automark = bw->automark_awar();
206        if (awar_automark->read_int()) { // just activated
207            LocallyModify<bool> avoid(avoid_recursion, true);
208
209            awar_automark->write_int(0);
210            BranchWindow *prev_active = findAutomarkingBranchWindow();
211            if (prev_active) prev_active->automark_awar()->write_int(0);
212            awar_automark->write_int(1);
213        }
214    }
215}
216
217void BranchWindow::create_awars(AW_root *aw_root) {
218    awar_info = aw_root->awar_string(local_awar_name(AWAR_BRANCH_ANALYSIS_TMP, "info"), "<No analysis performed yet>");
219    ntw->get_awar_tree()->add_callback(makeRootCallback(tree_changed_cb, this));
220
221    aw_root->awar_float(AWAR_BA_MIN_REL_DIFF, 75)->set_minmax(0, 100)->add_callback(makeRootCallback(mark_long_branches_automark_cb));
222    aw_root->awar_float(AWAR_BA_MIN_ABS_DIFF, 0.01)->set_minmax(0, 20)->add_callback(makeRootCallback(mark_long_branches_automark_cb));
223
224    aw_root->awar_int(AWAR_BA_MIN_DEPTH, 0)->set_minmax(0, 50)->add_callback(makeRootCallback(mark_deep_leafs_automark_cb));
225    aw_root->awar_float(AWAR_BA_MIN_ROOTDIST, 0.9)->set_minmax(0, 20)->add_callback(makeRootCallback(mark_deep_leafs_automark_cb));
226
227    aw_root->awar_float(AWAR_BA_DEGENERATION, 30)->set_minmax(0, 100)->add_callback(makeRootCallback(mark_degenerated_branches_automark_cb));
228}
229
230static AWT_config_mapping_def branch_analysis_config_mapping[] = {
231    { AWAR_BA_MIN_REL_DIFF, "minreldiff" },
232    { AWAR_BA_MIN_ABS_DIFF, "minabsdiff" },
233    { AWAR_BA_MIN_DEPTH,    "mindepth" },
234    { AWAR_BA_MIN_ROOTDIST, "minrootdist" },
235    { AWAR_BA_DEGENERATION, "degeneration" },
236
237    { NULp, NULp }
238};
239
240void BranchWindow::create_window(AW_root *aw_root) {
241    aws = new AW_window_simple;
242
243    aws->init(aw_root, GBS_global_string("BRANCH_ANALYSIS_%s", suffix), "Branch analysis");
244    aws->load_xfig("ad_branch.fig");
245
246    aws->auto_space(5, 5);
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("branch_analysis.hlp"));
254    aws->create_button("HELP", "HELP", "H");
255
256    AW_awar *awar_automark = aw_root->awar_int(automark_awarname(), 0);
257    aws->at("auto");
258    aws->label("Auto mark?");
259    aws->create_toggle(awar_automark->awar_name);
260    awar_automark->add_callback(makeRootCallback(automark_changed_cb, this));
261
262    aws->at("sel");
263    aws->create_button(NULp, ntw->get_awar_tree()->awar_name, NULp, "+");
264
265    aws->at("info");
266    aws->create_text_field(awar_info->awar_name);
267
268    aws->button_length(28);
269
270    aws->at("dist_analyse");
271    aws->callback(makeWindowCallback(distance_analysis_cb, this));
272    aws->create_button("ANALYSE", "Analyse distances in tree");
273
274    aws->at("unmark");
275    aws->callback(makeWindowCallback(unmark_branches_cb, this));
276    aws->create_button("UNMARK", "Unmark all species");
277
278    const int FIELDWIDTH  = 10;
279    const int SCALERWIDTH = 250;
280
281    aws->at("mark_long");
282    aws->callback(makeWindowCallback(mark_long_branches_cb, this));
283    aws->create_button("MARK_LONG", "Mark long branches");
284
285    aws->at("min_rel"); aws->create_input_field_with_scaler(AWAR_BA_MIN_REL_DIFF, FIELDWIDTH, SCALERWIDTH, AW_SCALER_LINEAR);
286    aws->at("min_abs"); aws->create_input_field_with_scaler(AWAR_BA_MIN_ABS_DIFF, FIELDWIDTH, SCALERWIDTH, AW_SCALER_EXP_LOWER);
287
288
289    aws->at("mark_deep");
290    aws->callback(makeWindowCallback(mark_deep_leafs_cb, this));
291    aws->create_button("MARK_DEEP", "Mark deep leafs");
292
293    aws->at("tree_depth");   aws->create_input_field_with_scaler(AWAR_BA_MIN_DEPTH,    FIELDWIDTH, SCALERWIDTH, AW_SCALER_EXP_LOWER);
294    aws->at("branch_depth"); aws->create_input_field_with_scaler(AWAR_BA_MIN_ROOTDIST, FIELDWIDTH, SCALERWIDTH, AW_SCALER_EXP_LOWER);
295
296    aws->at("mark_degen");
297    aws->callback(makeWindowCallback(mark_degenerated_branches_cb, this));
298    aws->create_button("MARK_DEGENERATED", "Mark degenerated branches");
299
300    aws->at("degen"); aws->create_input_field_with_scaler(AWAR_BA_DEGENERATION, FIELDWIDTH, SCALERWIDTH, AW_SCALER_EXP_LOWER);
301
302    aws->at("config");
303    AWT_insert_config_manager(aws, AW_ROOT_DEFAULT, "branch_analysis", branch_analysis_config_mapping);
304}
305
306AW_window *NT_create_branch_analysis_window(AW_root *aw_root, TREE_canvas *ntw) {
307    int ntw_id = ntw->get_index();
308    if (!existingBranchWindow[ntw_id]) {
309        existingBranchWindow[ntw_id] = new BranchWindow(aw_root, ntw);
310    }
311    nt_assert(existingBranchWindow[ntw_id]);
312    return existingBranchWindow[ntw_id]->get_window();
313}
314
Note: See TracBrowser for help on using the repository browser.