mosesdecoder/scripts/ems/web/sgviz.js

1704 lines
55 KiB
JavaScript

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;
}