diff options
Diffstat (limited to 'scripts/ems/web/sgviz.js')
-rw-r--r-- | scripts/ems/web/sgviz.js | 1703 |
1 files changed, 1703 insertions, 0 deletions
diff --git a/scripts/ems/web/sgviz.js b/scripts/ems/web/sgviz.js new file mode 100644 index 000000000..03ad4741a --- /dev/null +++ b/scripts/ems/web/sgviz.js @@ -0,0 +1,1703 @@ +var xmlns="http://www.w3.org/2000/svg"; +var RECOMBINED = 0; +var FROM = 1; +var TO = 2; +var OUTPUT = 3; +var ALIGNMENT = 4; +var CHILDREN = 5; +var RULE_SCORE = 6; +var HEURISTIC_RULE_SCORE = 7; +var HYP_SCORE = 8; +var LHS = 9; +var DERIVATION_SCORE = 10; +var CHART_WIDTH = window.innerWidth * 0.8; +var CHART_HEIGHT = window.innerHeight; +var CELL_WIDTH = CHART_WIDTH/input.length; +var CELL_HEIGHT = CHART_HEIGHT/(input.length+1); +var CELL_MARGIN = 4; +var CELL_BORDER = 2; +var CELL_PADDING = 2; +if (input.length < 6) { CELL_MARGIN = 5; CELL_BORDER = 3; CELL_PADDING = 3; } +if (input.length > 10) { CELL_MARGIN = 1; CELL_BORDER = 1; CELL_PADDING = 2; } +if (input.length > 20) { CELL_MARGIN = 0; CELL_BORDER = 0; CELL_PADDING = 1; } +var BUTTON_WIDTH = 170; +var BUTTON_HEIGHT = 30; +var OPTION_WIDTH = 60; +var OPTION_HEIGHT = BUTTON_HEIGHT; +var CELL_HIGHLIGHT_COLOR = "#c0ffc0"; +var CELL_REGULAR_COLOR = "#ffff80"; +var INPUT_HIGHLIGHT_COLOR = "#c0c0c0"; +var INPUT_REGULAR_COLOR = "#ffffff"; +var SORT_OPTION = 2; +var ZOOM = 0; +var ZOOM_FROM = 0; +var ZOOM_TO = input.length+1; +var ZOOM_WIDTH = input.length; + +var length = input.length; +var chart = document.getElementById("chart"); +var reachable = new Array(); +var cell_hyps = new Array(length); +var cell_derivation_score = Array(); + +// init basic layout +draw_chart(); +draw_menu(); +draw_options(); + +// process hypotheses +function process_hypotheses() { + index_hypotheses_by_cell(); + find_reachable_hypotheses(); + compute_best_derivation_scores(); +} + +// +// INITIALIZATION +// + +function index_hypotheses_by_cell() { + // init edge_lists + for(var from=0; from<length; from++) { + cell_hyps[from] = new Array(length); + for(var to=0; to<length; to++) { + cell_hyps[from][to] = new Array(); + } + } + // populate + for (var id in edge) { + var from = edge[id][FROM]; + var to = edge[id][TO]; + edge[id][FROM] = parseInt(from); + edge[id][TO] = parseInt(to); + edge[id][RULE_SCORE] = parseFloat(edge[id][RULE_SCORE]); + edge[id][HEURISTIC_RULE_SCORE] = parseFloat(edge[id][HEURISTIC_RULE_SCORE]); + edge[id][HYP_SCORE] = parseFloat(edge[id][HYP_SCORE]); + edge[id][DERIVATION_SCORE] = parseFloat(edge[id][DERIVATION_SCORE]); + cell_hyps[from][to].push(id); + } +} + +function find_reachable_hypotheses() { + for (var i=0;i<cell_hyps[0][length-1].length;i++) { + id = cell_hyps[0][length-1][i]; + find_reachable_hypotheses_recursive( id ); + } +} + +function find_reachable_hypotheses_recursive( id ) { + if (!(reachable[id] === undefined)) { return; } + reachable[id] = 1; + var children = get_children( id ); + for(var c=0;c<children.length;c++) { + find_reachable_hypotheses_recursive( children[c] ); + } +} + +function compute_best_derivation_scores() { + for(var from=0; from<length; from++ ) { + cell_derivation_score[from] = Array(); + } + for(var width=length-1; width>=0; width-- ) { + for(var from=0; from<length-width; from++ ) { + var to = from+width; + var cell_max_score = -9.9e9; + for (var i=0;i<cell_hyps[from][to].length;i++) { + var id = cell_hyps[from][to][i]; + if (width == length-1) { + edge[id][DERIVATION_SCORE] = edge[id][HYP_SCORE]; + } + if (edge[id][DERIVATION_SCORE] != null) { + var children = get_children(id); + for(var c=0;c<children.length;c++) { + if (edge[children[c]][DERIVATION_SCORE] == null || + edge[children[c]][DERIVATION_SCORE] < edge[id][DERIVATION_SCORE]) { + edge[children[c]][DERIVATION_SCORE] = edge[id][DERIVATION_SCORE]; + } + } + } + if (edge[id][DERIVATION_SCORE] != null && + edge[id][DERIVATION_SCORE] > cell_max_score) { + cell_max_score = edge[id][DERIVATION_SCORE]; + } + } + cell_derivation_score[from][to] = cell_max_score; + } + } +} + +// +// MENU +// + +function draw_menu() { + draw_menu_button(1,"Best Derivation"); + draw_menu_button(2,"Number of Hypotheses"); + draw_menu_button(3,"Number of Rule Cubes"); + draw_menu_button(4,"Derivation Score"); + draw_menu_button(5,"Non-Terminals") + draw_menu_button(6,"Hypotheses") +} +var MENU_POSITION_HYPOTHESES = 6; // where is "Hypotheses" in the menu? + +var current_menu_selection = 0; +var menu_processing = 0; +function click_menu( id, force_flag ) { + if (!force_flag && (menu_processing || current_menu_selection == id)) { + return; + } + menu_processing = 1; + + if (current_menu_selection == 1) { best_derivation(0); } + if (current_menu_selection == 2) { unannotate_cells(); } + if (current_menu_selection == 3) { unannotate_cells(); } + if (current_menu_selection == 4) { unannotate_cells(); } + if (current_menu_selection == 5) { remove_non_terminal_treemap(0); } + if (current_menu_selection == 6 && SORT_OPTION != 3) { remove_hypothesis_overview(); } + if (current_menu_selection == 6 && SORT_OPTION == 3) { remove_hypothesis_overview(); remove_non_terminal_treemap(); } + if (current_menu_selection > 0) { + highlight_menu_button( current_menu_selection, 0 ); + } + + if (id == 1) { best_derivation(1); } + if (id == 2) { annotate_cells_with_hypcount(); } + if (id == 3) { annotate_cells_with_rulecount(); } + if (id == 4) { annotate_cells_with_derivation_score(); } + if (id == 5) { non_terminal_treemap(); } + if (id == 6 && SORT_OPTION != 3) { hypothesis_overview(); } + if (id == 6 && SORT_OPTION == 3) { draw_hypothesis_sort_buttons(); non_terminal_treemap(1); } + highlight_menu_button( id, 1 ); + current_menu_selection = id; + menu_processing = 0; +} + +function draw_menu_button( id, label ) { + var button = document.createElementNS(xmlns,"rect"); + button.setAttribute("id", "button-" + id); + button.setAttribute("x", 5); + button.setAttribute("y", 5 + BUTTON_HEIGHT*(id-1)); + button.setAttribute("rx", 3); + button.setAttribute("ry", 3); + button.setAttribute("width", BUTTON_WIDTH-10); + button.setAttribute("height", BUTTON_HEIGHT-10); + //button.setAttribute("opacity",.75); + button.setAttribute("fill", "#c0c0ff"); + button.setAttribute("stroke", "black"); + button.setAttribute("stroke-width", "1"); + button.setAttribute("onclick","click_menu(" + id + ",0);") + chart.appendChild( button ); + + var button_label = document.createElementNS(xmlns,"text"); + button_label.setAttribute("x", BUTTON_WIDTH/2); + button_label.setAttribute("y", 4+BUTTON_HEIGHT/2 + BUTTON_HEIGHT*(id-1)); + button_label.setAttribute("style", "font-size: 12; font-family: Verdana, Arial;"); + button_label.setAttribute("text-anchor", "middle"); + button_label.setAttribute("pointer-events", "none"); + var content = document.createTextNode( label ); + button_label.appendChild( content ); + button_label.setAttribute("onclick","click_menu(" + id + ",0);") + + chart.appendChild( button_label ); +} + +function highlight_menu_button( id, on_off ) { + var button = document.getElementById("button-" + id); + if (on_off) { + button.setAttribute("fill", "#8080ff"); + } + else { + button.setAttribute("fill", "#c0c0ff"); + } +} + +// OPTIONS + +function draw_options() { + draw_option_button(0,1,"score"); + draw_option_button(0,2,"deriv."); + draw_option_button(0,3,"id"); +} + +function draw_rule_options() { + draw_option_button(1,1,"score"); + draw_option_button(1,2,"deriv."); + draw_option_button(1,3,"zoom"); + highlight_option_button(1,1,show_hyp_score); + highlight_option_button(1,2,show_derivation_score); +} + +function draw_option_button( rule_option, id, label ) { + var button = document.createElementNS(xmlns,"rect"); + button.setAttribute("id", (rule_option?"rule-":"") + "option-" + id); + button.setAttribute("x", rule_option ? CHART_WIDTH-BUTTON_WIDTH-OPTION_WIDTH : BUTTON_WIDTH+10); + button.setAttribute("y", 5 + OPTION_HEIGHT*(id-1)); + button.setAttribute("rx", 3); + button.setAttribute("ry", 3); + button.setAttribute("width", OPTION_WIDTH-10); + button.setAttribute("height", OPTION_HEIGHT-10); + button.setAttribute("fill", "#fdd017"); + button.setAttribute("stroke", "black"); + button.setAttribute("stroke-width", "1"); + button.setAttribute("onclick","click_"+(rule_option?"rule_":"")+"option(" + id + ");") + chart.appendChild( button ); + + var button_label = document.createElementNS(xmlns,"text"); + var distance_from_side = BUTTON_WIDTH+5+OPTION_WIDTH/2; + button_label.setAttribute("id", (rule_option?"rule-":"") + "option-label-" + id); + button_label.setAttribute("x", rule_option ? CHART_WIDTH-distance_from_side : distance_from_side); + button_label.setAttribute("y", 4+OPTION_HEIGHT/2 + OPTION_HEIGHT*(id-1)); + button_label.setAttribute("style", "font-size: 12; font-family: Verdana, Arial;"); + button_label.setAttribute("text-anchor", "middle"); + button_label.setAttribute("pointer-events", "none"); + var content = document.createTextNode( label ); + button_label.appendChild( content ); + + chart.appendChild( button_label ); +} + +function draw_sort_button( id, label ) { + var BASE_X = 5 + id/SORT_BUTTON_COUNT * (BUTTON_WIDTH-10+5); + var BASE_Y = -5 + BUTTON_HEIGHT * MENU_POSITION_HYPOTHESES; + var WIDTH = ((BUTTON_WIDTH-10+5)/SORT_BUTTON_COUNT)-5; + + var button = document.createElementNS(xmlns,"rect"); + + button.setAttribute("id", "sort-" + id); + button.setAttribute("x", BASE_X); + button.setAttribute("y", BASE_Y); + button.setAttribute("width", WIDTH); + button.setAttribute("height", BUTTON_HEIGHT-12); + if (id==0) { + button.setAttribute("fill", "none"); + } + else { + button.setAttribute("rx", 3); + button.setAttribute("ry", 3); + if (SORT_OPTION == id) { + button.setAttribute("fill", "#6080ff"); + } + else { + button.setAttribute("fill", "#a0c0ff"); + } + button.setAttribute("onclick","click_sort(" + id + ");") + button.setAttribute("stroke", "black"); + button.setAttribute("stroke-width", "1"); + } + chart.appendChild( button ); + + var button_label = document.createElementNS(xmlns,"text"); + button_label.setAttribute("id", "sort-label-" + id); + button_label.setAttribute("x", BASE_X + WIDTH/2); + button_label.setAttribute("y", BASE_Y + 12); + button_label.setAttribute("style", "font-size: 10; font-family: Verdana, Arial;"); + button_label.setAttribute("text-anchor", "middle"); + button_label.setAttribute("pointer-events", "none"); + var content = document.createTextNode( label ); + button_label.appendChild( content ); + + chart.appendChild( button_label ); +} + +function click_sort( id ) { + if (SORT_OPTION == 3) { + remove_non_terminal_treemap(1) + } + remove_hypothesis_overview(); + + SORT_OPTION = id; + + if (SORT_OPTION == 3) { + non_terminal_treemap(1); + draw_hypothesis_sort_buttons(); + } + else { + hypothesis_overview(); + } +} + +var show_scores = 0; +var show_id = 0; +var show_derivation = 0; +function click_option( id ) { + if (id == 1) { + show_scores = !show_scores; + highlight_option_button( 0, 1, show_scores ); + } + if (id == 2) { + show_derivation = !show_derivation; + color_cells(); + highlight_option_button( 0, 2, show_derivation ); + } + if (id == 3) { + show_id = !show_id; + highlight_option_button( 0, 3, show_id ); + } + if (current_menu_selection > 0) { + click_menu( current_menu_selection, 1 ); + } +} + +var show_hyp_score = 0; +var show_derivation_score = 0; +function click_rule_option( id ) { + if (id == 1) { + show_hyp_score = !show_hyp_score; + highlight_option_button( 1, 1, show_hyp_score ); + } + if (id == 2) { + show_derivation_score = !show_derivation_score; + highlight_option_button( 1, 2, show_derivation_score ); + } + if (id == 3) { + if (ZOOM > 0) { + ZOOM = 0; + } + else { + ZOOM = 0.3; + } + assign_chart_coordinates(); + highlight_option_button( 1, 3, ZOOM ); + } + draw_rule_cube(current_z_pos_string); +} + +function highlight_option_button( rule_option, id, on_off ) { + var button = document.getElementById((rule_option?"rule-":"") + "option-" + id); + if (on_off) { + button.setAttribute("fill", "#cd853f"); + } + else { + button.setAttribute("fill", "#fdd017"); + } +} + +// INITIALIZE THE CHART + +function draw_chart() { + for (var from=0;from<length;from++) { + for(var width=1; width<=length-from; width++) { + var to = from + width - 1; + + // logical container + var container = document.createElementNS(xmlns,"svg"); + container.setAttribute("id", "cell-container-" + from + "-" + to); + chart.appendChild( container ); + var transform = document.createElementNS(xmlns,"g"); + transform.setAttribute("id", "cell-" + from + "-" + to); + container.appendChild( transform ); + + // yellow box for the cell + var cell = document.createElementNS(xmlns,"rect"); + cell.setAttribute("id", "cellbox-" + from + "-" + to); + cell.setAttribute("x", CELL_MARGIN); + cell.setAttribute("y", CELL_MARGIN); + cell.setAttribute("rx", CELL_BORDER); + cell.setAttribute("ry", CELL_BORDER); + cell.setAttribute("width", CELL_WIDTH-2*CELL_MARGIN); + cell.setAttribute("height", CELL_HEIGHT-2*CELL_MARGIN); + cell.setAttribute("opacity", .75); + cell.setAttribute("fill", get_cell_color(from,to)); + cell.setAttribute("stroke", "black"); + cell.setAttribute("stroke-width", "1"); + cell.setAttribute("onmouseover","hover_cell(" + from + "," + to + ");") + cell.setAttribute("onclick","click_cell(" + from + "," + to + ");") + transform.appendChild( cell ); + } + + // box for the input word + var input_box = document.createElementNS(xmlns,"rect"); + input_box.setAttribute("id", "inputbox-" + from); + input_box.setAttribute("x", CELL_MARGIN+from*CELL_WIDTH); + input_box.setAttribute("y", CELL_MARGIN+(length)*CELL_HEIGHT); + input_box.setAttribute("rx", 3); + input_box.setAttribute("ry", 3); + input_box.setAttribute("width", CELL_WIDTH-2*CELL_MARGIN); + input_box.setAttribute("height", CELL_HEIGHT/2); + //cell.setAttribute("opacity", .75); + input_box.setAttribute("fill", INPUT_REGULAR_COLOR); + chart.appendChild( input_box ); + + // input word + input_word = document.createElementNS(xmlns,"text"); + input_word.setAttribute("id", "input-" + from); + input_word.setAttribute("x", (from+0.5)*CELL_WIDTH); + input_word.setAttribute("y", 10+(length+0.25)*CELL_HEIGHT); + input_word.setAttribute("style", "font-size:18;"); + input_word.setAttribute("text-anchor", "middle"); + var content = document.createTextNode( input[from] ); + input_word.appendChild( content ); + chart.appendChild( input_word ); + } + assign_chart_coordinates(); +} + +function assign_chart_coordinates() { + for (var from=0;from<length;from++) { + for(var width=1; width<=length-from; width++) { + var to = from + width - 1; + + var x = from*CELL_WIDTH + (width-1)*CELL_WIDTH/2; + var y = (length-width)*CELL_HEIGHT*(1-ZOOM); + //alert("(x,y) = (" + length + "," + width + "), width = " + ZOOM + ", height = " + (1-ZOOM)); + var cell_width = CELL_WIDTH; + var cell_height = CELL_HEIGHT; + if (ZOOM > 0) { + // adjust (x,y) + if (width > ZOOM_WIDTH) { // above + } + else if (width == ZOOM_WIDTH) { // same level + x = from*CELL_WIDTH*(1-ZOOM) + (width-1)*CELL_WIDTH*(1-ZOOM)/2 + if (from < ZOOM_FROM) { // left + y += (CHART_HEIGHT-2*CELL_HEIGHT)*ZOOM/2; + } + else if (from == ZOOM_FROM) { // the focus + } + else { // right + x += CHART_WIDTH*ZOOM; + y += (CHART_HEIGHT-2*CELL_HEIGHT)*ZOOM/2; + } + } + else { // below + y += CHART_HEIGHT*ZOOM-CELL_HEIGHT*(1-ZOOM); + } + + // adjust width and height + if (width == ZOOM_WIDTH) { // same level + cell_width *= 1-ZOOM; + if (from < ZOOM_FROM) { // left + } + else if (from == ZOOM_FROM) { // the focus + cell_width += CHART_WIDTH*ZOOM; + cell_height = CHART_HEIGHT*ZOOM; + } + } + else { + cell_height *= 1-ZOOM; + } + } + + var container = document.getElementById("cell-container-" + from + "-" + to); + container.setAttribute("x", x); + container.setAttribute("y", y); + var transform = document.getElementById("cell-" + from + "-" + to); + transform.setAttribute("transform", "scale(" + (cell_width/CELL_WIDTH) + "," + (cell_height/CELL_HEIGHT) + ")"); + } + } +} + +function remove_chart() { + for (var from=0;from<length;from++) { + for(var width=1; width<=length-from; width++) { + var to = from + width - 1; + var container = document.getElementById("cell-" + from + "-" + to); + chart.removeChild(container); + var cell = document.getElementById("cellbox-" + from + "-" + to); + chart.removeChild(cell); + } + var input_word = document.getElementById("input-" + from); + chart.removeChild(input_word); + var input_box = document.getElementById("inputbox-" + from); + chart.removeChild(input_box); + } +} + +var current_from = -1; +var current_to; +function hover_cell( from, to ) { + if (current_from >= 0) { + highlight_input( current_from, current_to, 0) + } + highlight_input( from, to, 1) + current_from = from; + current_to = to; +} + +function click_cell( from, to ) { + if (from == current_rule_from && to == current_rule_to) { + unshow_rules(); + current_rule_from = -1; + ZOOM = 0; + } + else { + show_rules( from, to ); + ZOOM_FROM = current_rule_from; + ZOOM_TO = current_rule_to; + ZOOM_WIDTH = to-from+1; + } + assign_chart_coordinates(); +} + +function highlight_input( from, to, on_off ) { + for(var i=from; i<=to; i++) { + var input_box = document.getElementById("inputbox-" + i); + input_box.setAttribute("fill", on_off ? INPUT_HIGHLIGHT_COLOR : INPUT_REGULAR_COLOR); + } +} + +// +// VISUALIZATION OF CHART CELLS +// + +// BASIC ANNOTATION WITH NUMBERS + +function annotate_cells_with_hypcount() { + for (var from=0;from<length;from++) { + for(var width=1; width<=length-from; width++) { + var to = from + width - 1; + annotate_cell( from, to, cell_hyps[from][to].length, 20 ) + } + } +} + +function annotate_cells_with_rulecount() { + for (var from=0;from<length;from++) { + for(var width=1; width<=length-from; width++) { + var to = from + width - 1; + var rule_hash = Array(); + var rule_count = 0; + for (var i=0;i<cell_hyps[from][to].length;i++) { + var rule = get_rule( cell_hyps[from][to][i] ); + if (rule_hash[rule] === undefined) { + rule_hash[rule] = 1; + rule_count++; + } + } + annotate_cell( from, to, rule_count, 20 ) + } + } +} + +function annotate_cells_with_derivation_score() { + for (var from=0;from<length;from++) { + for(var width=1; width<=length-from; width++) { + var to = from + width - 1; + var score = cell_derivation_score[from][to]; + if (score < -9e9) { score = "dead end"; } + annotate_cell( from, to, score, 15 ) + } + } +} + +function annotate_cell( from, to, label, font_size ) { + var cell_label_group = document.createElementNS(xmlns,"svg"); + cell_label_group.setAttribute("id", "celllabel-" + from + "-" + to); + cell_label_group.setAttribute("x", 0); + cell_label_group.setAttribute("y", -3); + cell_label_group.setAttribute("pointer-events", "none"); + + label = "" + label; // make it a string, if not already + var line = label.split("<br>"); + for(var i=0; i<line.length; i++) { + var cell_label = document.createElementNS(xmlns,"text"); + cell_label.setAttribute("id", "celllabelline-" + from + "-" + to + "-" + i); + cell_label.setAttribute("x", CELL_WIDTH/2); + cell_label.setAttribute("y", CELL_HEIGHT/2 + font_size * (1 - line.length/2 + i)); + cell_label.setAttribute("style", "font-size: " + font_size + ";font-family: Verdana, Arial;"); + cell_label.setAttribute("pointer-events", "none"); + cell_label.setAttribute("text-anchor", "middle"); + var content = document.createTextNode(line[i]); + cell_label.appendChild( content ); + cell_label_group.appendChild( cell_label ); + } + + var cell = document.getElementById("cell-" + from + "-" + to); + cell.appendChild( cell_label_group ); +} + +function unannotate_cells() { + for (var from=0;from<length;from++) { + for(var width=1; width<=length-from; width++) { + var to = from + width - 1; + unannotate_cell( from, to ); + } + } +} + +function unannotate_cell( from, to ) { + var cell = document.getElementById("cell-" + from + "-" + to); + var cell_label = document.getElementById("celllabel-" + from + "-" + to); + cell.removeChild(cell_label); +} + +// NON-TERMINAL TREEMAP + +function non_terminal_treemap( with_hyps ) { + for (var from=0;from<length;from++) { + for(var width=1; width<=length-from; width++) { + var to = from + width - 1; + // get nt counts + var lhs = new Array(); + var lhs_list = new Array(); + for (var i=0;i<cell_hyps[from][to].length;i++) { + var id = cell_hyps[from][to][i]; + var nt = edge[id][LHS]; + if (lhs[nt] === undefined) { + lhs[nt] = 1; + lhs_list.push(nt); + } + else { + lhs[nt]++; + } + } + // sort + function sortByCount(a,b) { + return lhs[b] - lhs[a]; + } + lhs_list.sort(sortByCount); + treemap_squarify( from, to, lhs_list, lhs, cell_hyps[from][to].length, with_hyps ); + } + } +} + +function remove_non_terminal_treemap() { + for (var from=0;from<length;from++) { + for(var width=1; width<=length-from; width++) { + var to = from + width - 1; + var cell = document.getElementById("cell-" + from + "-" + to); + var done = false; + var j=0; + while(!done) { + var rect = document.getElementById("rect-" + from + "-" + to + "-" + j); + if (rect == null) { + done = true; + } + else { + cell.removeChild(rect); + var rect_label = document.getElementById("rect-label-" + from + "-" + to + "-" + j); + if (rect_label != null) { + cell.removeChild(rect_label); + } + } + j++; + } + } + } +} + +function treemap_cell( from, to, label, count, total, with_hyps ) { + var cell = document.getElementById("cell-" + from + "-" + to); + var x = CELL_MARGIN; + var y = CELL_MARGIN; + var width = CELL_WIDTH - 2*CELL_MARGIN; + var height = CELL_HEIGHT - 2*CELL_MARGIN; + // TO DO + for (var i=0;i<label.length;i++) { + var rect = document.createElementNS(xmlns,"rect"); + rect.setAttribute("id", "-" + id); + rect.setAttribute("x", x); + rect.setAttribute("y", y); + rect.setAttribute("width", width * count[label[i]] / total); + rect.setAttribute("height", height); + rect.setAttribute("opacity",.75); + rect.setAttribute("fill", "#c0c0ff"); + rect.setAttribute("stroke", "black"); + rect.setAttribute("stroke-width", "0.5"); + rect.setAttribute("onclick","click_menu(" + id + ",0);") + cell.appendChild( rect ); + x += width * count[label[i]] / total; + } +} + +function treemap_squarify( from, to, label, count, total, with_hyps ) { + var cell = document.getElementById("cell-" + from + "-" + to); + // conversion of counts to area + var width = CELL_WIDTH - 2*CELL_MARGIN; + var height = CELL_HEIGHT - 2*CELL_MARGIN; + var area_factor = width*height / total; + var scale_factor = Math.sqrt( area_factor ); + width /= scale_factor; + height /= scale_factor; + var offset_x = 0; + var offset_y = 0; + + // main algorithm + var extend = Math.min(width,height); + var current_worst = squarify_worst( label, count, 0, 0, extend ); + var start = 0; + for(var i=1; i<=label.length; i++) { + // add to sequence or start new one? + var next_worst = 0; + if (i != label.length) { + next_worst = squarify_worst( label, count, start, i, extend ); + } + if (i != label.length && current_worst >= next_worst) { + current_worst = next_worst; // ... and keep going + } + else { + // compute rectangles... + var sum = 0; + for(var j=start; j<i; j++) { + sum += count[label[j]]; + } + var cum_x = 0; + var cum_y = 0; + var remaining_ratio = sum / ((width - offset_x) * (height - offset_y)); + var this_width = (width - offset_x) * remaining_ratio; + var this_height = (height - offset_y) * remaining_ratio; + var adding_on_left = height-offset_y < width-offset_x; + for(var j=start; j<i; j++) { + if (adding_on_left) { this_height = count[label[j]] / sum * (height - offset_y); } + else { this_width = count[label[j]] / sum * (width - offset_x); } + // rectangle + var rect = document.createElementNS(xmlns,"rect"); + rect.setAttribute("id", "rect-" + from + "-" + to + "-" + j); + rect.setAttribute("x", CELL_MARGIN + (offset_x + cum_x) * scale_factor); + rect.setAttribute("y", CELL_MARGIN + (offset_y + cum_y) * scale_factor); + rect.setAttribute("width", this_width * scale_factor); + rect.setAttribute("height", this_height * scale_factor); + rect.setAttribute("fill-opacity",0); + rect.setAttribute("pointer-events", "none"); + rect.setAttribute("stroke", "black"); + rect.setAttribute("stroke-width", "0.5"); + cell.appendChild( rect ); + // hypotheses + if (with_hyps) { + var hyp_list = Array(); + for(var k=0; k<cell_hyps[from][to].length; k++) { + var id = cell_hyps[from][to][k]; + var nt = edge[id][LHS]; + if (nt == label[j]) { + hyp_list.push( id ); + } + } + hypothesis_in_rect( this_width * scale_factor - 2, + this_height * scale_factor - 2, + CELL_MARGIN + (offset_x + cum_x) * scale_factor + 1, + CELL_MARGIN + (offset_y + cum_y) * scale_factor + 1, + cell, hyp_list ); + } + // label + var font_size = Math.min( Math.round(this_width * scale_factor / label[j].length * 1.3), + Math.round(this_height * scale_factor )); + if (font_size > 20) { font_size = 20; } + if (font_size >= 3) { + var rect_label = document.createElementNS(xmlns,"text"); + rect_label.setAttribute("id", "rect-label-" + from + "-" + to + "-" + j); + rect_label.setAttribute("x", CELL_MARGIN + (offset_x + cum_x + this_width/2) * scale_factor); + rect_label.setAttribute("y", CELL_MARGIN + (offset_y + cum_y + this_height/2) * scale_factor + font_size/2 -2); + rect_label.setAttribute("style", "font-size: " + font_size + "; font-family: Verdana, Arial; font-weight:900;"); + rect_label.setAttribute("fill", "#00f"); + rect_label.setAttribute("opacity", .3); + rect_label.setAttribute("text-anchor", "middle"); + rect_label.setAttribute("pointer-events", "none"); + var content = document.createTextNode( label[j] ); + rect_label.appendChild( content ); + cell.appendChild( rect_label ); + } + if (adding_on_left) { cum_y += this_height; } + else { cum_x += this_width; } + } + if (adding_on_left) { offset_x += this_width; } + else { offset_y += this_height; } + + // move to next sequence + if (i != label.length) { + start = i; + extend = Math.min( width-offset_x, height-offset_y ); + current_worst = squarify_worst( label, count, i, i, extend ); + } + } + } +} + +function squarify_worst( label, count, start, end, extend ) { + var sum = 0; + for(var i=start; i<=end; i++) { + sum += count[label[i]]; + } + var max_ratio = 0; + for(var i=start; i<=end; i++) { + var ratio = count[label[i]] * extend*extend /sum/sum; + if (ratio < 1) { ratio = 1/ratio; } + max_ratio = Math.max( ratio, max_ratio ); + } + return max_ratio; +} + +// HIGHLIGHT BEST DERIVATION + +function best_derivation( on_off ) { + var best_score = -9e9; + var best_id = -1; + for (var i=0;i<cell_hyps[0][length-1].length;i++) { + id = cell_hyps[0][length-1][i]; + if (edge[id][HYP_SCORE] > best_score) { + best_score = edge[id][HYP_SCORE]; + best_id = id; + } + } + best_derivation_recurse( best_id, on_off, -1, -1, 0 ); +} + +function best_derivation_recurse( id, on_off, parent_from, parent_to, child_pos ) { + var from = edge[id][FROM]; + var to = edge[id][TO]; + + // highlight cell and annotate with rule + highlight_cell( from, to, on_off ); + if (on_off) { + var annotation = ""; + if (show_id) { annotation += id + "<br>"; } + annotation += edge[id][LHS] + "\u2192"; + annotation += edge[id][OUTPUT]; + if (show_scores) { annotation += "<br>" + edge[id][HYP_SCORE]; } + annotate_cell( from, to, annotation, 10 ); + } + else { + unannotate_cell( from, to ); + } + + // highlight hyp + highlight_hyp( id, on_off ); + + // arrow to parent + if (parent_from >= 0) { + if (on_off) { + make_arrow( id, parent_from, parent_to, from, to, 0, child_pos ); + } + else { + var arrow = document.getElementById("arrow-" + id); + chart.removeChild(arrow); + } + } + + var child_order = Array(); + if (edge[id][ALIGNMENT] != "") { + var alignment = edge[id][ALIGNMENT].split(" "); + // sorting: array position is source nonterminal pos + alignment.sort(); + // alignment target sympol pos -> source nonterminal pos + var reversed_alignment = Array(); + for(var i=0; i<alignment.length; i++) { + var source_target = alignment[i].split("-"); + reversed_alignment.push(source_target[1]+"-"+i); + } + // sorting by symbols pos: array position is nonterminal pos + reversed_alignment.sort(); + // mapping child -> target nonterminal pos + for(var i=0; i<reversed_alignment.length; i++) { + var target_source = reversed_alignment[i].split("-"); + child_order[target_source[1]] = i; + } + } + + // recurse + var covered = new Array; + var children = get_children( id ); + for(var c=0;c<children.length;c++) { + var child = children[c]; + for( var i=edge[child][FROM]; i<=edge[child][TO]; i++ ) { + covered[i] = 1; + } + best_derivation_recurse( child, on_off, from, to, children.length == 1 ? 0.5 : child_order[c]/(children.length-1.0) ); + } + + // arrows to words + for( var i=from; i<=to; i++ ) { + if (covered[i] === undefined) { + if (on_off) { + make_arrow( "word-" + i, from, to, i, i, 1, 0.5 ); + } + else { + var arrow = document.getElementById("arrow-word-" + i); + chart.removeChild(arrow); + } + } + } +} + +function make_arrow( id, parent_from, parent_to, from, to, word_flag, position ) { + var arrow = document.createElementNS(xmlns,"line"); + arrow.setAttribute("id", "arrow-" + id); + + var parent = get_cellbox_coordinates( parent_from, parent_to ); + arrow.setAttribute("x1", parent.x+(0.5+position)/2*CELL_WIDTH*parent.scale_x); + arrow.setAttribute("y1", parent.y+(CELL_HEIGHT-CELL_MARGIN)*parent.scale_y); + + if (word_flag) { + arrow.setAttribute("x2", (from+.5)*CELL_WIDTH); + arrow.setAttribute("y2", CELL_MARGIN+length*CELL_HEIGHT); + } + else { + var child = get_cellbox_coordinates( from, to ); + arrow.setAttribute("x2", child.x+child.scale_x*CELL_WIDTH/2); + arrow.setAttribute("y2", child.y+child.scale_y*CELL_MARGIN+word_flag*(CELL_HEIGHT+5)); + } + + arrow.setAttribute("stroke", word_flag ? "#808080" : "#008000"); + arrow.setAttribute("stroke-width", "3"); + chart.appendChild( arrow ); +} + +function get_cellbox_coordinates(from, to) { + var container = document.getElementById("cell-container-" + from + "-" + to); + var transform = document.getElementById("cell-" + from + "-" + to); + var scale = transform.getAttribute("transform").split(/[\(\),]/g); + var scale_x = scale[1]; + var scale_y = scale[2]; + return { x: Math.round(container.getAttribute("x")), + y: Math.round(container.getAttribute("y")), + scale_x: scale[1], + scale_y: scale[2] + } +} + +function highlight_cell( from, to, on_off ) { + var cell = document.getElementById("cellbox-" + from + "-" + to); + cell.setAttribute("fill", on_off ? CELL_HIGHLIGHT_COLOR : get_cell_color(from,to) ); +} + +function color_cells() { + for (var from=0;from<length;from++) { + for(var width=1; width<=length-from; width++) { + var to = from+width-1; + highlight_cell(from,to,0); + } + } +} + +function get_cell_color( from, to ) { + if (!show_derivation) { + return CELL_REGULAR_COLOR; + } + var score_diff = cell_derivation_score[from][to] - cell_derivation_score[0][length-1]; + var dec = 128 - (score_diff*8); + if (dec>255) { dec = 255; } + var color = Math.round(dec).toString(16); + return "#ffff"+color; +} + +function get_children( id ) { + if (edge[id][CHILDREN] == "") { + return []; + } + return edge[id][CHILDREN].split(" "); +} + +// OVERVIEW ALL HYPOTHESES +function hypothesis_overview() { + for (var from=0;from<length;from++) { + for(var width=1; width<=length-from; width++) { + var to = from + width - 1; + hypothesis_overview_cell( from, to ); + } + } + draw_hypothesis_sort_buttons(); +} + +function draw_hypothesis_sort_buttons() { + // draw sort buttons + draw_sort_button(0,"sort by"); + draw_sort_button(1,"id"); + draw_sort_button(2,"score"); + draw_sort_button(3,"lhs"); +} +var SORT_BUTTON_COUNT = 4; // how many in total (incl. "sort by")? + +function hypothesis_overview_cell( from, to ) { + var width = CELL_WIDTH-2*(CELL_BORDER+CELL_MARGIN+CELL_PADDING); + var height = CELL_HEIGHT-2*(CELL_BORDER+CELL_MARGIN+CELL_PADDING); + var cell = document.getElementById("cell-" + from + "-" + to); + hypothesis_in_rect( width, height, CELL_BORDER+CELL_MARGIN+CELL_PADDING, CELL_BORDER+CELL_MARGIN+CELL_PADDING, cell, cell_hyps[from][to] ); +} + +function hypothesis_in_rect( width, height, offset_x, offset_y, parent_element, hyp_list ) { + + // diameter, based on perfect fill + var diameter = Math.sqrt( width * height / hyp_list.length ); + // if it does not fit the discrete objects, increase + while( Math.floor( width/diameter ) * Math.floor( height/diameter ) < hyp_list.length ) { + diameter = Math.max( width / Math.ceil( width/diameter + 0.0001 ), // fitting one more in row + height / Math.ceil( height/diameter + 0.0001 ) ); // fitting one more in column + } + var row_size = Math.floor( width / diameter ); + var column_size = Math.floor( height / diameter ); + + // sort hypotheses + function sortByScore(a,b) { + return edge[b][HYP_SCORE] - edge[a][HYP_SCORE]; + } + function sortById(a,b) { + return a-b; + } + if (SORT_OPTION == 1) { + hyp_list.sort(sortById); + } + else { + hyp_list.sort(sortByScore); + } + + // draw hypothesis + var x=0 + var y=0; + var column = 0; + + for (var i=0; i<hyp_list.length;i++) { + id = hyp_list[i]; + + //alert("adding circle (" + (x + diameter/2) + "," + (y + diameter/2) + ") - " + (diameter/2) ); + var hyp = document.createElementNS(xmlns,"circle"); + hyp.setAttribute("id", "hyp-" + id); + hyp.setAttribute("cx", x + diameter/2 + offset_x); + hyp.setAttribute("cy", y + diameter/2 + offset_y); + hyp.setAttribute("r", diameter/2); + hyp.setAttribute("fill", hyp_color(id, 0)); + hyp.setAttribute("onmouseover","hover_hyp(" + id + ");") + hyp.setAttribute("onmouseout","unhover_hyp(" + id + ");") + parent_element.appendChild( hyp ); + + x += diameter; + if (++column >= row_size) { + column = 0; + y += diameter; + x = 0; + } + } +} + +function remove_hypothesis_overview() { + for (var id in edge) { + var cell = document.getElementById("cell-" + edge[id][FROM] + "-" + edge[id][TO]); + var hyp = document.getElementById("hyp-" + id); + cell.removeChild(hyp); + } + // remove sort buttons + for(var i=0; i<4; i++) { + var old = document.getElementById("sort-" + i); + chart.removeChild( old ); + var old = document.getElementById("sort-label-" + i); + chart.removeChild( old ); + } +} + +function hover_hyp( id ) { + best_derivation_recurse( id, 1, -1, -1 ); +} + +function unhover_hyp( id ) { + best_derivation_recurse( id, 0, -1, -1 ); +} + +function hover_rule_hyp( id ) { + highlight_rule_hyp( id, 1 ); + if (current_menu_selection == 1) { + best_derivation( 0 ); + } + if (current_menu_selection <= 2) { + best_derivation_recurse( id, 1, -1, -1 ); + } +} + +function unhover_rule_hyp( id ) { + highlight_rule_hyp( id, 0 ); + if (current_menu_selection <= 2) { + best_derivation_recurse( id, 0, -1, -1 ); + } + if (current_menu_selection == 1) { + best_derivation( 1 ); + } +} + +function highlight_hyp( id, on_off ) { + var hyp = document.getElementById("hyp-" + id); + if (hyp == null) { return; } + hyp.setAttribute("fill", hyp_color(id, on_off)); +} + +function highlight_rule_hyp( id, on_off ) { + var hyp = document.getElementById("rule-hyp-" + id); + if (hyp == null) { return; } + hyp.setAttribute("fill", rule_hyp_color(id, on_off)); +} + +function hyp_color( id, on_off ) { + if (on_off) { + var color = "#ff0000"; + if (edge[id][RECOMBINED]>0) { color = "#808080"; } + else if (id in reachable) { color = "#00c000"; } + return color; + } + var color = "#ffc0c0"; + if (edge[id][RECOMBINED]>0) { color = "#c0c0c0"; } + else if (id in reachable) { color = "#80ff80"; } + return color; +} + +// RULES + +function get_rule( id ) { + // get non-terminal labels + if (edge[id] === undefined) { alert("unknown edge "+id); return ""; } + var output = edge[id][OUTPUT].split(" "); + var alignment = edge[id][ALIGNMENT].split(" "); + alignment.sort(); + var nt_label = Array(); + for(var i=0;i<alignment.length;i++) { + var source_target = alignment[i].split("-"); + nt_label.push(output[source_target[1]]); + } + + var rule = edge[id][LHS]+"\u2192"; + var children = get_children(id); + var pos = edge[id][FROM]; + for (var i=0; i<children.length; i++) { + if (pos != edge[id][FROM]) { rule += " "; } + var child = children[i]; + for(;pos<edge[child][FROM];pos++) { + rule += (input[pos].length <= 10) ? input[pos] : input[pos].substr(0,8) + "."; + rule += " "; + } + rule += nt_label[i]; + rule += (edge[child][FROM] == edge[child][TO]) ? + "[" + edge[child][FROM] + "]" : + "[" + edge[child][FROM] + "-" + edge[child][TO] + "]"; + pos = edge[child][TO]+1; + } + for(;pos<=edge[id][TO];pos++) { + if (pos != edge[id][FROM]) { rule += " "; } + rule += (input[pos].length <= 10) ? input[pos] : input[pos].substr(0,8) + "."; + } + + return rule; +} + +var rule_list; +var edge2rule; +var current_rule_from = -1; +var current_rule_to; +var RULE_HEIGHT; +var RULE_FONT_SIZE; +var best_hyp_score; +var best_derivation_score; +function show_rules( from, to ) { + unshow_rules(); + var cell = document.getElementById("cellbox-" + from + "-" + to); + cell.setAttribute("stroke", "#800000"); + cell.setAttribute("stroke-width", "3"); + current_rule_from = from; + current_rule_to = to; + + best_hyp_score = -9e9; + best_derivation_score = cell_derivation_score[from][to]; + + var rule_hash = Array(); + var rule_count = Array(); + rule_list = Array(); + edge2rule = Array(); + for (var i=0;i<cell_hyps[from][to].length;i++) { + var id = cell_hyps[from][to][i]; + var rule = get_rule( id ); + if (rule_hash[rule] === undefined) { + rule_hash[rule] = rule_list.length; + rule_count[rule_list.length] = 1; + rule_list.push(rule); + } + else { + rule_count[rule_hash[rule]]++; + } + edge2rule[id] = rule_hash[rule]; + + if (edge[id][HYP_SCORE] > best_hyp_score) { + best_hyp_score = edge[id][HYP_SCORE]; + } + } + function sortByRuleCount( a, b ) { + return rule_count[rule_hash[b]] - rule_count[rule_hash[a]]; + } + rule_list = rule_list.sort(sortByRuleCount); + + RULE_HEIGHT = 15; + RULE_FONT_SIZE = 11; + // squeeze if too many rules + if (rule_list.length * RULE_HEIGHT > (CHART_HEIGHT-50)) { + var factor = (CHART_HEIGHT-50)/rule_list.length/RULE_HEIGHT; + RULE_HEIGHT = Math.floor( RULE_HEIGHT * factor ); + RULE_FONT_SIZE = Math.ceil( RULE_FONT_SIZE * factor ); + } + + draw_rule_options(); + for(var i=-1; i<rule_list.length; i++) { + draw_rule(from, to, i); + } + if (rule_list.length > 0) { + click_rule( from, to, 0 ); + } +} + +function unshow_rules() { + if (current_rule_from >= 0) { + var cell = document.getElementById("cellbox-" + current_rule_from + "-" + current_rule_to); + cell.setAttribute("stroke", "black"); + cell.setAttribute("stroke-width", "1"); + } + var finished = 0; + for(var i=-1; !finished; i++) { + var old = document.getElementById("rule-" + i); + if (old != null) { chart.removeChild( old ); } + else { finished = 1; } + } + var old = document.getElementById("rule-message"); + if (old != null) { chart.removeChild( old ); } + old = document.getElementById("rule-cube"); + if (old != null) { chart.removeChild( old ); } + finished = 0; + for(var i=1; !finished; i++) { + var old = document.getElementById("rule-option-" + i); + if (old != null) { + chart.removeChild( old ); + var old = document.getElementById("rule-option-label-" + i); + chart.removeChild( old ); + } + else { finished = 1; } + } +} + +function draw_rule( from, to, rule_id ) { + var rule_label = document.createElementNS(xmlns,"text"); + rule_label.setAttribute("id", "rule-" + rule_id); + rule_label.setAttribute("x", CHART_WIDTH-120); + rule_label.setAttribute("y", 10 + RULE_HEIGHT*(rule_id+1)); + rule_label.setAttribute("text-anchor", "middle"); + if (rule_id>-1) { + rule_label.setAttribute("style", "font-size: "+RULE_FONT_SIZE+"; font-family: Verdana, Arial;"); + rule_label.setAttribute("onclick","click_rule(" + from + "," + to + "," + rule_id + ");"); + var content = document.createTextNode( rule_list[rule_id] ); + rule_label.appendChild( content ); + } + else { + rule_label.setAttribute("style", "font-size: "+(RULE_FONT_SIZE-2)+"; font-family: Verdana, Arial; font-weight: bold;"); + var content = document.createTextNode( rule_list.length == 0 ? "NO RULES" : "RULES" ); + rule_label.appendChild( content ); + } + chart.appendChild( rule_label ); +} + +function draw_rule_message( message ) { + var old = document.getElementById("rule-message"); + if (old != null) { chart.removeChild( old ); } + + var rule_message_group = document.createElementNS(xmlns,"svg"); + rule_message_group.setAttribute("id","rule-message"); + rule_message_group.setAttribute("x", 0); + rule_message_group.setAttribute("y", 250); + var line = message.split("<br>"); + for(var i=0;i<line.length;i++) { + var line_label = document.createElementNS(xmlns,"text"); + line_label.setAttribute("id", "rule-message-line" + id); + line_label.setAttribute("x", 0); + line_label.setAttribute("y", RULE_HEIGHT*(i+1)); + line_label.setAttribute("style", "font-size: 9; font-family: Verdana, Arial;"); + var content = document.createTextNode( line[i] ); + line_label.appendChild( content ); + rule_message_group.appendChild( line_label ); + } + chart.appendChild( rule_message_group ); +} + +var output_list; +var children_list; +var current_edge; +var current_rule_id = -1; +var axis; +var dimension_order; +var RULE_CUBE_HYP_SIZE; +var RULE_CUBE_FONT_SIZE; +function click_rule( from, to, rule_id ) { + // highlight current rule + if (current_rule_id>=0) { + var rule_label = document.getElementById("rule-"+current_rule_id); + rule_label.setAttribute("style", "font-size: "+RULE_FONT_SIZE+"; font-family: Verdana, Arial;"); + } + var rule_label = document.getElementById("rule-"+rule_id); + rule_label.setAttribute("style", "font-size: "+RULE_FONT_SIZE+"; font-family: Verdana, Arial; font-weight: bold;"); + current_rule_id = rule_id; + + // first get all the data + output_list = Array(); + var output_hash = Array(); + children_list = Array(); + var children_hash = Array(); + current_edge = Array(); + for (var i=0;i<cell_hyps[from][to].length;i++) { + var id = cell_hyps[from][to][i]; + var rule = get_rule( id ); + if (rule == rule_list[rule_id]) { + current_edge.push( id ); + // create index for output (target rhs) + var output = edge[id][OUTPUT]+"|"+edge[id][HEURISTIC_RULE_SCORE]; + if (output_hash[output] === undefined) { + output_hash[output] = output_list.length; + output_list.push(output); + } + // create index for children + var children = get_children( id ); + for(var j=0;j<children.length;j++) { + // init children indices if needed + if (j > children_list.length-1) { + children_hash.push([]); + children_list.push([]); + } + // build index + var child = ""+children[j]; + if (children_hash[j][child] === undefined) { + children_hash[j][child] = children_list[j].length; + children_list[j].push(parseInt(child)); + } + } + } + } + + // sort + function sortBySecond(a,b) { + asplit = a.split("|"); + bsplit = b.split("|"); + return bsplit[1] - asplit[1]; + } + output_list = output_list.sort(sortBySecond); + + function sortHypByScore(a,b) { + return edge[b][HYP_SCORE] - edge[a][HYP_SCORE]; + } + for(var i=0;i<children.length;i++) { + children_list[i].sort(sortHypByScore); + } + + // select dimensions of rule cube + axis = Array(); + axis.push(output_list); + for(var i=0;i<children_list.length;i++) { + axis.push(children_list[i]); + } + + // determine order + var dimension_size = Array(); + for(var i=0;i<axis.length;i++) { + dimension_size.push(i+"|"+(axis[i].length - i/10)); + } + dimension_size.sort(sortBySecond); + dimension_order = Array(); + for(var i=0;i<dimension_size.length;i++) { + id_size = dimension_size[i].split("|"); + dimension_order.push(id_size[0]); + } + + var z_pos = Array(); + for(i=2;i<axis.length;i++) { z_pos.push(0); } + var z_pos_string = z_pos.join(","); + draw_rule_cube(z_pos.join(",")); +} + +var current_z_pos_string = ""; +function draw_rule_cube(z_pos_string) { + current_z_pos_string = z_pos_string; + var z_pos = Array(); + if (z_pos_string != "") { + z_pos = z_pos_string.split(","); + } + + // draw rube cube + var old = document.getElementById("rule-cube"); + if (old != null) { chart.removeChild( old ); } + + // dimensions of the 2x2 view + var max_length = axis[dimension_order[0]].length; + //if (axis.length>1 && axis[dimension_order[1]].length > max_length) { + // max_length = axis[dimension_order[1]].length; + //} + + // space for additional dimensions + var z_dimension_length = 0; + if (dimension_order.length > 2) { + z_dimension_length = -2; + for(var i=2; i<dimension_order.length; i++ ) { + z_dimension_length += axis[dimension_order[i]].length + 2; + max_length += axis[dimension_order[i]].length + 2; + } + } + //if (dimension_order.length > 2) { + // for(var i=2; i<dimension_order.length; i++ ) { + // if (axis[dimension_order[i]].length > max_z_dimension_length) { + // max_z_dimension_length = axis[dimension_order[i]].length; + // } + // } + //} + //if (max_z_dimension_length > 10) { + // max_z_dimension_length = 10; + //} + //var y_length = axis[dimension_order[0]].length; + //if (max_z_dimension_length > 0) { + // y_length += max_z_dimension_length + 2; + // if (y_length > max_length) { + // max_length = y_length; + // } + //} + + // calculate table cell and font size + if (max_length+8 <= CHART_HEIGHT/15) { + RULE_CUBE_HYP_SIZE = 15; + RULE_CUBE_FONT_SIZE = 11; + } + else if (max_length+8 > CHART_HEIGHT/9) { + RULE_CUBE_HYP_SIZE = 9; + RULE_CUBE_FONT_SIZE = 7; + } + else { + RULE_CUBE_HYP_SIZE = CHART_HEIGHT/(max_length+8); + RULE_CUBE_FONT_SIZE = (RULE_CUBE_HYP_SIZE * 12/15).toFixed(0); + } + var Z_HEIGHT = 0; + if (dimension_order.length > 2) { + Z_HEIGHT = (z_dimension_length + 2) * RULE_CUBE_HYP_SIZE; + } + + var rule_cube = document.createElementNS(xmlns,"svg"); + rule_cube.setAttribute("id","rule-cube"); + rule_cube.setAttribute("x", CHART_WIDTH - 30); + rule_cube.setAttribute("y", 0); + chart.appendChild( rule_cube ); + + // draw y axis + var label = get_rule_axis_name(dimension_order[0]); + draw_rule_row(-1,label); + for(var y=0; y<axis[dimension_order[0]].length; y++) { + var label = get_rule_axis_label(dimension_order[0], y); + draw_rule_row(y,label); + } + if (axis[dimension_order[0]].length > (CHART_HEIGHT-Z_HEIGHT)/9-10) { + draw_rule_row(Math.ceil(CHART_HEIGHT/9-10),"(more, "+axis[dimension_order[0]].length+" total)"); + } + + // draw x axis + if (axis.length > 1) { + var label = get_rule_axis_name(dimension_order[1]); + draw_rule_column(-1,label); + for(var x=0; x<axis[dimension_order[1]].length && x<CHART_HEIGHT/9-10; x++) { + var label = get_rule_axis_label(dimension_order[1], x); + draw_rule_column(x,label); + } + if (axis[dimension_order[1]].length > CHART_HEIGHT/9-10) { + draw_rule_column(Math.ceil(CHART_HEIGHT/9-10),"(more, "+axis[dimension_order[1]].length+" total)"); + } + } + + // draw hyps + for(var y=0; y<axis[dimension_order[0]].length && y<(CHART_HEIGHT-Z_HEIGHT)/9-10; y++) { + if (axis.length == 1) { + var hyp = find_hyp_by_rule([y],dimension_order); + draw_rule_hyp(0,y,hyp); + } + else { + for(var x=0; x<axis[dimension_order[1]].length && x<CHART_HEIGHT/9-10; x++) { + var hyp = find_hyp_by_rule([y,x].concat(z_pos),dimension_order); + draw_rule_hyp(x,y,hyp); + } + } + } + + + // draw z-axes + var pos_offset = axis[dimension_order[0]].length+2; + for(var z=2;z<dimension_order.length;z++) { + var label = get_rule_axis_name(dimension_order[z]); + draw_rule_z(z-2,dimension_order.length-2, z_pos, -1, pos_offset, label); + for(var i=0;i<axis[dimension_order[z]].length && i<z_dimension_length; i++) { + var label = get_rule_axis_label(dimension_order[z], i); + draw_rule_z(z-2,dimension_order.length-2, z_pos, i, pos_offset, label); + } + pos_offset += axis[dimension_order[z]].length+2; + } + + // report summary statistics + var message = output_list.length + " output phrases"; + message += "<br>DEBUG: " + axis.length; + message += "<br>" + dimension_order.length; + for(var i=0;i<children_list.length;i++) { + message += "<br>" + children_list[i].length + " hyps for NT" + (i+1); + } + //draw_rule_message(message); +} + +function find_hyp_by_rule(position, dimension_order) { + for(var e=0;e<current_edge.length;e++) { + var id = current_edge[e]; + var children = get_children( id ); + var match = 1; + for(var p=0; p<position.length; p++) { + if (dimension_order[p] == 0) { + if (output_list[position[p]] != edge[id][OUTPUT]+"|"+edge[id][HEURISTIC_RULE_SCORE]) { + match = 0; + } + } + else { + var nt_number = dimension_order[p]-1; + if (children_list[nt_number][position[p]] != children[nt_number]) { + match = 0; + } + } + } + if (match) { return id; } + } + return -1; +} + +function get_rule_axis_label( dimension, i ) { + if (dimension == 0) { + var output_score = output_list[i].split("|"); + var score = 1 * output_score[1]; + return output_score[0]+" "+score.toFixed(1); + } + var id = children_list[dimension-1][i]; + return get_display_output( id ) + " " + edge[id][HYP_SCORE].toFixed(1); +} + +function get_rule_axis_name( dimension ) { + if (dimension == 0) { + return "TARGET"; + } + return "NT" + dimension; +} + + +function get_display_output( id ) { + var output_string = get_full_output( id ); + var output = output_string.split(" "); + if (output.length <= 2) { + return output_string; + } + else { + return output[0] + "\u203B" + output[output.length-1]; + } +} + +function get_full_output( id ) { + var output = edge[id][OUTPUT].split(" "); + + var alignment = edge[id][ALIGNMENT].split(" "); + var children = get_children( id ); + alignment.sort(); + var nonterminal = Array(); + for(var i=0; i<alignment.length; i++) { + var source_target = alignment[i].split("-"); + nonterminal[source_target[1]] = children[i]; + } + + var full_output = ""; + for(var i=0;i<output.length;i++) { + if (nonterminal[i] === undefined) { + full_output += " " + output[i]; + } + else { + full_output += " " + get_full_output( nonterminal[i] ); + } + } + return full_output.substr(1); +} + +function draw_rule_row( pos, label ) { + var rule_label = document.createElementNS(xmlns,"text"); + rule_label.setAttribute("id", "rule-row-" + pos); + rule_label.setAttribute("y", RULE_CUBE_FONT_SIZE*10 + RULE_CUBE_HYP_SIZE*pos); + if (pos>=0) { + rule_label.setAttribute("style", "font-size: "+RULE_CUBE_FONT_SIZE+"; font-family: Verdana, Arial;"); + rule_label.setAttribute("x", RULE_CUBE_FONT_SIZE*10+5); + } + else { + rule_label.setAttribute("style", "font-size: "+(RULE_CUBE_FONT_SIZE-2)+"; font-family: Verdana, Arial; font-weight: bold;"); + rule_label.setAttribute("x", RULE_CUBE_FONT_SIZE*10-30); + } + rule_label.setAttribute("text-anchor", "end"); + var content = document.createTextNode( label ); + rule_label.appendChild( content ); + var rule_cube = document.getElementById("rule-cube"); + rule_cube.appendChild( rule_label ); +} + +function draw_rule_column( pos, label ) { + var rule_label = document.createElementNS(xmlns,"text"); + rule_label.setAttribute("id", "rule-column-" + pos); + rule_label.setAttribute("x", RULE_CUBE_FONT_SIZE*10 -3 + RULE_CUBE_HYP_SIZE*(1+pos) ); + rule_label.setAttribute("y", RULE_CUBE_FONT_SIZE*10 -12); + rule_label.setAttribute("transform", "rotate(60 "+ (RULE_CUBE_FONT_SIZE*10-3+RULE_CUBE_HYP_SIZE*(1+pos)) +" "+(RULE_CUBE_FONT_SIZE*10 - 12)+")") + if (pos>=0) { + rule_label.setAttribute("style", "font-size: "+RULE_CUBE_FONT_SIZE+"; font-family: Verdana, Arial;"); + } + else { + rule_label.setAttribute("style", "font-size: "+(RULE_CUBE_FONT_SIZE-2)+"; font-family: Verdana, Arial; font-weight: bold;"); + } + rule_label.setAttribute("text-anchor", "end"); + var content = document.createTextNode( label ); + rule_label.appendChild( content ); + var rule_cube = document.getElementById("rule-cube"); + rule_cube.appendChild( rule_label ); +} + +function draw_rule_z( z,total_z, z_pos, pos,pos_offset, label ) { + var rule_label = document.createElementNS(xmlns,"text"); + rule_label.setAttribute("id", "rule-z-" + z + "-" + pos); + //rule_label.setAttribute("x", RULE_CUBE_FONT_SIZE*10+10 + CHART_HEIGHT*z/(total_z+1) ); + rule_label.setAttribute("x", RULE_CUBE_FONT_SIZE*10+10 ); + rule_label.setAttribute("y", RULE_CUBE_FONT_SIZE*10 + RULE_CUBE_HYP_SIZE*(pos+pos_offset)); + if (pos >= 0) { + rule_label.setAttribute("style", "font-size: "+RULE_CUBE_FONT_SIZE+"; font-family: Verdana, Arial;" + +((z_pos[z] == pos)?" font-weight: bold;":"")); + z_pos_copy = z_pos.join(",").split(","); + z_pos_copy[z] = pos; + rule_label.setAttribute("onclick","draw_rule_cube(\"" + z_pos_copy.join(",") + "\");"); + } + else { + rule_label.setAttribute("style", "font-size: "+(RULE_CUBE_FONT_SIZE-2)+"; font-family: Verdana, Arial; font-weight: bold;"); + } + + var content = document.createTextNode( label ); + rule_label.appendChild( content ); + var rule_cube = document.getElementById("rule-cube"); + rule_cube.appendChild( rule_label ); +} + +function draw_rule_hyp( xpos, ypos, id ) { + if (id == -1) { return; } + var diameter = RULE_CUBE_HYP_SIZE-2; + var hyp = document.createElementNS(xmlns,"circle"); + hyp.setAttribute("id", "rule-hyp-" + id); + hyp.setAttribute("cx", RULE_CUBE_FONT_SIZE*10+10 + RULE_CUBE_HYP_SIZE*xpos + diameter/2); + hyp.setAttribute("cy", RULE_CUBE_FONT_SIZE*10-2 + RULE_CUBE_HYP_SIZE*(ypos-0.5) + diameter/2); + hyp.setAttribute("r", diameter/2); + hyp.setAttribute("fill", rule_hyp_color(id, 0)); + //hyp.setAttribute("opacity",.5); + hyp.setAttribute("onmouseover","hover_rule_hyp(" + id + ");") + hyp.setAttribute("onmouseout","unhover_rule_hyp(" + id + ");") + var rule_cube = document.getElementById("rule-cube"); + rule_cube.appendChild( hyp ); +} + +function rule_hyp_color( id, on_off ) { + if (!show_hyp_score && !show_derivation_score) { + return hyp_color( id, on_off ); + } + var inactive_color = on_off ? "80" : "00"; + var hyp_score_color = inactive_color; + var derivation_score_color = inactive_color; + if (show_hyp_score) { + hyp_score_color = get_score_from_color(best_hyp_score-edge[id][HYP_SCORE]); + } + if (show_derivation_score) { + if (edge[id][DERIVATION_SCORE] == null) { + derivation_score_color = "00"; + } + else { + derivation_score_color = get_score_from_color(best_derivation_score-edge[id][DERIVATION_SCORE]); + } + } + return "#" + inactive_color + derivation_score_color + hyp_score_color; +} + +function get_score_from_color( score, on_off ) { + if (score == null) { return "00"; } + var dec = 255 - 255 * (score/8); + if (dec < 0) { dec = 0; } + if (on_off) { dec = dec/2+128; } + dec = Math.floor(dec/16)*16+15; + var color = dec.toString(16); + if (dec < 16) { color = "0"+color; } + return color; +} |