ARB
NT_branchAnalysis.cxx
Go to the documentation of this file.
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 <awt_canvas.hxx>
16 #include <aw_msg.hxx>
17 #include <aw_root.hxx>
18 #include <awt_config_manager.hxx>
19 
20 #define AWAR_BRANCH_ANALYSIS "branch_analysis"
21 #define AWAR_BRANCH_ANALYSIS_TMP "tmp/" AWAR_BRANCH_ANALYSIS
22 
23 #define AWAR_BA_MIN_REL_DIFF AWAR_BRANCH_ANALYSIS "/min_rel_diff"
24 #define AWAR_BA_MIN_ABS_DIFF AWAR_BRANCH_ANALYSIS "/min_abs_diff"
25 #define AWAR_BA_MIN_DEPTH AWAR_BRANCH_ANALYSIS "/min_depth"
26 #define AWAR_BA_MIN_ROOTDIST AWAR_BRANCH_ANALYSIS "/min_rootdist"
27 #define AWAR_BA_DEGENERATION AWAR_BRANCH_ANALYSIS "/degeneration"
28 
29 #define AWAR_BA_AUTOMARK_FORMAT AWAR_BRANCH_ANALYSIS_TMP "/auto_%s"
30 
31 // AISC_MKPT_PROMOTE:class TREE_canvas;
32 
33 class BranchWindow : virtual Noncopyable {
34  TREE_canvas *ntw;
35  char *suffix;
36  AW_awar *awar_info;
37  AW_window_simple *aws;
38 
39  static char *get_suffix(TREE_canvas *ntw) {
40  // suffix depends on canvas
41  return GBS_global_string_copy("_%i", ntw->get_index());
42  }
43 
44  const char *local_awar_name (const char *prefix, const char *name) { return GBS_global_string("%s%s/%s", prefix, suffix, name); }
45 
46  void create_awars(AW_root *aw_root);
47  void create_window(AW_root *aw_root);
48 
49  const char *automark_awarname() const { return GBS_global_string(AWAR_BA_AUTOMARK_FORMAT, suffix); }
50 
51 public:
52  BranchWindow(AW_root *aw_root, TREE_canvas *ntw_)
53  : ntw(ntw_),
54  suffix(get_suffix(ntw))
55  {
56  create_awars(aw_root);
57  create_window(aw_root);
58  }
59 
61  free(suffix);
62  }
63 
64  AW_window *get_window() const { return aws; }
65 
66 private:
67  AW_root *get_awroot() const { return get_window()->get_root(); }
68  TREE_canvas *get_canvas() const { return ntw; }
69  AP_tree *get_tree() const { return AWT_TREE(ntw)->get_root_node(); }
70  GBDATA *get_gbmain() const { return get_canvas()->gb_main; }
71  AW_awar *awar(const char *name) { return get_awroot()->awar(name); }
72 
73  void postmark_action() const {
74  AWT_auto_refresh allowed_on(get_canvas());
75  get_canvas()->request_structure_update();
76  }
77 
78  bool have_tree() {
79  if (get_tree()) return true;
80  set_info("No tree selected");
81  return false;
82  }
83 
84  static void adapt_intawar_max(AW_awar *awar, int val, int extra) { // @@@ move to AW_awar?
85  // adapt maximum defined for int-awar (according to encountered maximum 'val' + a bit 'extra' range)
86  nt_assert(awar->get_type() == AW_INT);
87 
88  int max = awar->get_max();
89  if (max<val || ((val*2) < max && awar->get_min()<val)) {
90  awar->set_max(val+extra);
91  }
92  }
93  static void adapt_floatawar_max(AW_awar *awar, double val, double extra) { // @@@ move to AW_awar?
94  // adapt maximum defined for float-awar (according to encountered maximum 'val' + a bit 'extra' range)
95  nt_assert(awar->get_type() == AW_FLOAT);
96 
97  double max = awar->get_max();
98  if (max<val || ((val*2) < max && awar->get_min()<val)) {
99  awar->set_max(val+extra);
100  }
101  }
102 
103 public:
104  void set_info(const char *msg) const { awar_info->write_string(msg); }
105  void unmark_all() const { NT_mark_all_cb(NULp, get_canvas(), 0); }
106 
107  AW_awar *automark_awar() const { return get_awroot()->awar(automark_awarname()); }
108  bool has_automark_set() const { return automark_awar()->read_int(); }
109 
111  if (have_tree()) {
112  GB_transaction ta(get_gbmain());
113 
114  AW_awar *awar_degen = awar(AWAR_BA_DEGENERATION);
115  double degeneration_factor = awar_degen->read_float();
116 
117  unmark_all();
118 
119  double found_max_degeneration = get_tree()->mark_degenerated_branches(degeneration_factor);
120  set_info(GBS_global_string("Maximum degeneration = %.2f", found_max_degeneration));
121  adapt_floatawar_max(awar_degen, found_max_degeneration, 1.0);
122 
123  postmark_action();
124  }
125  }
126  void markDeepLeafs() {
127  if (have_tree()) {
128  GB_transaction ta(get_gbmain());
129 
130  AW_awar *awar_min_depth = awar(AWAR_BA_MIN_DEPTH);
131  AW_awar *awar_min_rootdist = awar(AWAR_BA_MIN_ROOTDIST);
132  int min_depth = awar_min_depth->read_int();
133  double min_rootdist = awar_min_rootdist->read_float();
134  int found_max_depth;
135  double found_max_rootdist;
136 
137  unmark_all();
138  set_info(get_tree()->mark_deep_leafs(min_depth, min_rootdist, found_max_depth, found_max_rootdist));
139  adapt_intawar_max(awar_min_depth, found_max_depth, 1);
140  adapt_floatawar_max(awar_min_rootdist, found_max_rootdist, 0.1);
141  postmark_action();
142  }
143  }
145  if (have_tree()) {
146  GB_transaction ta(get_gbmain());
147 
148  AW_awar *awar_abs_diff = awar(AWAR_BA_MIN_ABS_DIFF);
149  double min_rel_diff = awar(AWAR_BA_MIN_REL_DIFF)->read_float()/100.0;
150  double min_abs_diff = awar_abs_diff->read_float();
151  double found_max_abs_diff;
152 
153  unmark_all();
154  set_info(get_tree()->mark_long_branches(min_rel_diff, min_abs_diff, found_max_abs_diff));
155  adapt_floatawar_max(awar_abs_diff, found_max_abs_diff, 0.1);
156  postmark_action();
157  }
158  }
159 
161  if (have_tree()) {
162  GB_transaction ta(get_gbmain());
163  set_info(get_tree()->analyse_distances());
164  }
165  }
166 };
167 
169 
170 // --------------------------------------------------------------------------------
171 
175 static void unmark_branches_cb (AW_window*, BranchWindow *bw) { bw->unmark_all(); }
177 
178 static void tree_changed_cb (AW_root*, BranchWindow *bw) { bw->set_info("<tree has changed>"); }
179 
181  for (int w = 0; w<MAX_NT_WINDOWS; ++w) {
182  BranchWindow *bw = existingBranchWindow[w];
183  if (bw && bw->has_automark_set()) {
184  return bw;
185  }
186  }
187  return NULp;
188 }
189 
192  if (bw) bw->markLongBranches();
193 }
196  if (bw) bw->markDeepLeafs();
197 }
200  if (bw) bw->markDegeneratedBranches();
201 }
202 
204  static bool avoid_recursion = false;
205  if (!avoid_recursion) {
206  AW_awar *awar_automark = bw->automark_awar();
207  if (awar_automark->read_int()) { // just activated
208  LocallyModify<bool> avoid(avoid_recursion, true);
209 
210  awar_automark->write_int(0);
211  BranchWindow *prev_active = findAutomarkingBranchWindow();
212  if (prev_active) prev_active->automark_awar()->write_int(0);
213  awar_automark->write_int(1);
214  }
215  }
216 }
217 
218 void BranchWindow::create_awars(AW_root *aw_root) {
219  awar_info = aw_root->awar_string(local_awar_name(AWAR_BRANCH_ANALYSIS_TMP, "info"), "<No analysis performed yet>");
220  ntw->get_awar_tree()->add_callback(makeRootCallback(tree_changed_cb, this));
221 
222  aw_root->awar_float(AWAR_BA_MIN_REL_DIFF, 75)->set_minmax(0, 100)->add_callback(makeRootCallback(mark_long_branches_automark_cb));
223  aw_root->awar_float(AWAR_BA_MIN_ABS_DIFF, 0.01)->set_minmax(0, 20)->add_callback(makeRootCallback(mark_long_branches_automark_cb));
224 
225  aw_root->awar_int(AWAR_BA_MIN_DEPTH, 0)->set_minmax(0, 50)->add_callback(makeRootCallback(mark_deep_leafs_automark_cb));
226  aw_root->awar_float(AWAR_BA_MIN_ROOTDIST, 0.9)->set_minmax(0, 20)->add_callback(makeRootCallback(mark_deep_leafs_automark_cb));
227 
229 }
230 
232  { AWAR_BA_MIN_REL_DIFF, "minreldiff" },
233  { AWAR_BA_MIN_ABS_DIFF, "minabsdiff" },
234  { AWAR_BA_MIN_DEPTH, "mindepth" },
235  { AWAR_BA_MIN_ROOTDIST, "minrootdist" },
236  { AWAR_BA_DEGENERATION, "degeneration" },
237 
238  { NULp, NULp }
239 };
240 
241 void BranchWindow::create_window(AW_root *aw_root) {
242  aws = new AW_window_simple;
243 
244  aws->init(aw_root, GBS_global_string("BRANCH_ANALYSIS_%s", suffix), "Branch analysis");
245  aws->load_xfig("ad_branch.fig");
246 
247  aws->auto_space(5, 5);
248 
249  aws->at("close");
250  aws->callback(AW_POPDOWN);
251  aws->create_button("CLOSE", "CLOSE", "C");
252 
253  aws->at("help");
254  aws->callback(makeHelpCallback("branch_analysis.hlp"));
255  aws->create_button("HELP", "HELP", "H");
256 
257  AW_awar *awar_automark = aw_root->awar_int(automark_awarname(), 0);
258  aws->at("auto");
259  aws->label("Auto mark?");
260  aws->create_toggle(awar_automark->awar_name);
261  awar_automark->add_callback(makeRootCallback(automark_changed_cb, this));
262 
263  aws->at("sel");
264  aws->create_button(NULp, ntw->get_awar_tree()->awar_name, NULp, "+");
265 
266  aws->at("info");
267  aws->create_text_field(awar_info->awar_name);
268 
269  aws->button_length(28);
270 
271  aws->at("dist_analyse");
272  aws->callback(makeWindowCallback(distance_analysis_cb, this));
273  aws->create_button("ANALYSE", "Analyse distances in tree");
274 
275  aws->at("unmark");
276  aws->callback(makeWindowCallback(unmark_branches_cb, this));
277  aws->create_button("UNMARK", "Unmark all species");
278 
279  const int FIELDWIDTH = 10;
280  const int SCALERWIDTH = 250;
281 
282  aws->at("mark_long");
283  aws->callback(makeWindowCallback(mark_long_branches_cb, this));
284  aws->create_button("MARK_LONG", "Mark long branches");
285 
286  aws->at("min_rel"); aws->create_input_field_with_scaler(AWAR_BA_MIN_REL_DIFF, FIELDWIDTH, SCALERWIDTH, AW_SCALER_LINEAR);
287  aws->at("min_abs"); aws->create_input_field_with_scaler(AWAR_BA_MIN_ABS_DIFF, FIELDWIDTH, SCALERWIDTH, AW_SCALER_EXP_LOWER);
288 
289 
290  aws->at("mark_deep");
291  aws->callback(makeWindowCallback(mark_deep_leafs_cb, this));
292  aws->create_button("MARK_DEEP", "Mark deep leafs");
293 
294  aws->at("tree_depth"); aws->create_input_field_with_scaler(AWAR_BA_MIN_DEPTH, FIELDWIDTH, SCALERWIDTH, AW_SCALER_EXP_LOWER);
295  aws->at("branch_depth"); aws->create_input_field_with_scaler(AWAR_BA_MIN_ROOTDIST, FIELDWIDTH, SCALERWIDTH, AW_SCALER_EXP_LOWER);
296 
297  aws->at("mark_degen");
298  aws->callback(makeWindowCallback(mark_degenerated_branches_cb, this));
299  aws->create_button("MARK_DEGENERATED", "Mark degenerated branches");
300 
301  aws->at("degen"); aws->create_input_field_with_scaler(AWAR_BA_DEGENERATION, FIELDWIDTH, SCALERWIDTH, AW_SCALER_EXP_LOWER);
302 
303  aws->at("config");
304  AWT_insert_config_manager(aws, AW_ROOT_DEFAULT, "branch_analysis", branch_analysis_config_mapping);
305 }
306 
308  int ntw_id = ntw->get_index();
309  if (!existingBranchWindow[ntw_id]) {
310  existingBranchWindow[ntw_id] = new BranchWindow(aw_root, ntw);
311  }
312  nt_assert(existingBranchWindow[ntw_id]);
313  return existingBranchWindow[ntw_id]->get_window();
314 }
315 
#define AWAR_BRANCH_ANALYSIS_TMP
#define AWT_TREE(ntw)
Definition: TreeDisplay.hxx:85
static void mark_long_branches_cb(AW_window *, BranchWindow *bw)
static void automark_changed_cb(AW_root *, BranchWindow *bw)
void NT_mark_all_cb(UNFIXED, TREE_canvas *ntw, int mark_mode)
AW_window * get_window() const
static AWT_config_mapping_def branch_analysis_config_mapping[]
void AWT_insert_config_manager(AW_window *aww, AW_default default_file_, const char *id, const StoreConfigCallback &store_cb, const RestoreConfigCallback &load_or_reset_cb, const char *macro_id, const AWT_predefined_config *predef)
long read_int() const
Definition: AW_awar.cxx:184
#define AWAR_BA_MIN_ROOTDIST
AW_awar * set_minmax(float min, float max)
Definition: AW_awar.cxx:530
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:203
void AW_POPDOWN(AW_window *window)
Definition: AW_window.cxx:52
#define AWAR_BA_MIN_REL_DIFF
BranchWindow(AW_root *aw_root, TREE_canvas *ntw_)
static void mark_long_branches_automark_cb()
static void mark_degenerated_branches_cb(AW_window *, BranchWindow *bw)
AW_VARIABLE_TYPE get_type() const
Definition: AW_awar.cxx:262
#define MAX_NT_WINDOWS_NULLINIT
Definition: NT_local.h:33
AW_awar * set_max(float max)
Definition: aw_awar.hxx:146
AW_awar * add_callback(const RootCallback &cb)
Definition: AW_awar.cxx:231
static BranchWindow * findAutomarkingBranchWindow()
WindowCallback makeHelpCallback(const char *helpfile)
Definition: aw_window.hxx:106
#define AWAR_BA_AUTOMARK_FORMAT
static void distance_analysis_cb(AW_window *, BranchWindow *bw)
AW_awar * awar_float(const char *var_name, float default_value=0.0, AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:560
AW_awar * automark_awar() const
void markDegeneratedBranches()
static void unmark_branches_cb(AW_window *, BranchWindow *bw)
void unmark_all() const
#define MAX_NT_WINDOWS
Definition: NT_local.h:32
float get_max() const
Definition: AW_awar.cxx:555
#define AWAR_BA_MIN_DEPTH
AW_awar * awar(const char *awar)
Definition: AW_root.cxx:554
float get_min() const
Definition: AW_awar.cxx:544
float read_float() const
Definition: AW_awar.cxx:177
int get_index() const
double mark_degenerated_branches(double degeneration_factor)
Definition: AP_Tree.cxx:1496
#define nt_assert(cond)
Definition: NT_local.h:27
char * awar_name
Definition: aw_awar.hxx:103
AW_awar * awar_int(const char *var_name, long default_value=0, AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:580
void request_structure_update()
Definition: awt_canvas.hxx:365
static void tree_changed_cb(AW_root *, BranchWindow *bw)
void set_info(const char *msg) const
AW_root * get_root()
Definition: aw_window.hxx:359
#define NULp
Definition: cxxforward.h:116
GB_ERROR write_string(const char *aw_string)
#define AWAR_BA_DEGENERATION
static BranchWindow * existingBranchWindow[MAX_NT_WINDOWS]
bool has_automark_set() const
GB_transaction ta(gb_var)
AW_awar * awar_string(const char *var_name, const char *default_value="", AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:570
AW_window * NT_create_branch_analysis_window(AW_root *aw_root, TREE_canvas *ntw)
static void mark_deep_leafs_automark_cb()
static void mark_deep_leafs_cb(AW_window *, BranchWindow *bw)
static void mark_degenerated_branches_automark_cb()
AW_awar * get_awar_tree() const
#define AWAR_BA_MIN_ABS_DIFF
#define AW_ROOT_DEFAULT
Definition: aw_base.hxx:106
GB_ERROR write_int(long aw_int)
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:194
GBDATA * gb_main
Definition: awt_canvas.hxx:336
#define max(a, b)
Definition: f2c.h:154