|
CorpusAnnotationDiff |
|
1 /* 2 * CorpusAnnotationDiff.java 3 * 4 * Copyright (c) 1998-2001, The University of Sheffield. 5 * 6 * This file is part of GATE (see http://gate.ac.uk/), and is free 7 * software, licenced under the GNU Library General Public License, 8 * Version 2, June 1991 (in the distribution as file licence.html, 9 * and also available at http://gate.ac.uk/gate/licence.html). 10 * 11 * Angel Kirilov (mod. AnnotationDiff), 22/Aug/2002 12 * 13 * $Id: CorpusAnnotationDiff.java,v 1.2 2002/12/16 08:26:43 nasso Exp $ 14 */ 15 16 package gate.annotation; 17 18 import java.util.*; 19 import java.awt.*; 20 import java.text.NumberFormat; 21 import java.awt.event.*; 22 import javax.swing.*; 23 import javax.swing.table.*; 24 25 import gate.util.*; 26 import gate.annotation.*; 27 import gate.*; 28 import gate.gui.*; 29 import gate.swing.*; 30 import gate.creole.*; 31 import java.beans.*; 32 33 /** 34 * This class compare two annotation sets on annotation type given by the 35 * AnnotationSchema object. It also deals with graphic representation of the 36 * result. 37 */ 38 public class CorpusAnnotationDiff extends AbstractVisualResource 39 implements Scrollable{ 40 41 // number of pixels to be used as increment by scroller 42 protected int maxUnitIncrement = 10; 43 44 /** Debug flag */ 45 private static final boolean DEBUG = false; 46 47 /** This document contains the key annotation set which is taken as reference 48 * in comparison*/ 49 private Document keyDocument = null; 50 51 /** This corpus contains the key annotation set which is taken as reference 52 * in comparison*/ 53 private Corpus keyCorpus = null; 54 55 /** The name of the annotation set. If is null then the default annotation set 56 * will be considered. 57 */ 58 private String keyAnnotationSetName = null; 59 60 /** This document contains the response annotation set which is being 61 * compared against the key annotation set. 62 */ 63 private Document responseDocument = null; 64 65 /** This corpus contains the response annotation set which is being 66 * compared against the key annotation set. 67 */ 68 private Corpus responseCorpus = null; 69 70 /** The name of the annotation set. If is null then the default annotation set 71 * will be considered. 72 */ 73 private String responseAnnotationSetName = null; 74 75 /** The name of the annotation set considered in calculating FalsePozitive. 76 * If is null then the default annotation set will be considered. 77 */ 78 private String responseAnnotationSetNameFalsePoz = null; 79 80 /** The annotation schema object used to get the annotation name*/ 81 private AnnotationSchema annotationSchema = null; 82 83 /** A set of feature names bellonging to annotations from keyAnnotList 84 * used in isCompatible() and isPartiallyCompatible() methods 85 */ 86 private Set keyFeatureNamesSet = null; 87 88 /** The precision strict value (see NLP Information Extraction)*/ 89 private double precisionStrict = 0.0; 90 /** The precision lenient value (see NLP Information Extraction)*/ 91 private double precisionLenient = 0.0; 92 /** The precision average value (see NLP Information Extraction)*/ 93 private double precisionAverage = 0.0; 94 95 /** The Recall strict value (see NLP Information Extraction)*/ 96 private double recallStrict = 0.0; 97 /** The Recall lenient value (see NLP Information Extraction)*/ 98 private double recallLenient = 0.0; 99 /** The Recall average value (see NLP Information Extraction)*/ 100 private double recallAverage = 0.0; 101 102 /** The False positive strict (see NLP Information Extraction)*/ 103 private double falsePositiveStrict = 0.0; 104 /** The False positive lenient (see NLP Information Extraction)*/ 105 private double falsePositiveLenient = 0.0; 106 /** The False positive average (see NLP Information Extraction)*/ 107 private double falsePositiveAverage = 0.0; 108 109 /** The F-measure strict (see NLP Information Extraction)*/ 110 private double fMeasureStrict = 0.0; 111 /** The F-measure lenient (see NLP Information Extraction)*/ 112 private double fMeasureLenient = 0.0; 113 /** The F-measure average (see NLP Information Extraction)*/ 114 private double fMeasureAverage = 0.0; 115 /** The weight used in F-measure (see NLP Information Extraction)*/ 116 public static double weight = 0.5; 117 118 /** This string represents the type of annotations used to play the roll of 119 * total number of words needed to calculate the False Positive. 120 */ 121 private String annotationTypeForFalsePositive = null; 122 123 /** A number formater for displaying precision and recall*/ 124 protected static NumberFormat formatter = NumberFormat.getInstance(); 125 126 /** The components that will stay into diffPanel*/ 127 private XJTable diffTable = null; 128 129 /** Used to represent the result of diff. See DiffSetElement class.*/ 130 private Set diffSet = null; 131 132 /** This field is used in doDiff() and detectKeyType() methods and holds all 133 * partially correct keys */ 134 private Set keyPartiallySet = null; 135 /** This field is used in doDiff() and detectResponseType() methods*/ 136 private Set responsePartiallySet = null; 137 138 /** This list is created from keyAnnotationSet at init() time*/ 139 private java.util.List keyAnnotList = null; 140 /** This list is created from responseAnnotationSet at init() time*/ 141 private java.util.List responseAnnotList = null; 142 143 /** This field indicates wheter or not the annot diff should run int the text 144 * mode*/ 145 private boolean textMode = false; 146 147 /** Field designated to represent the max nr of annot types and coolors for 148 * each type 149 **/ 150 public static final int MAX_TYPES = 5; 151 /** A default type when all annotation are the same represented by White color*/ 152 public static final int DEFAULT_TYPE = 0; 153 /** A correct type when all annotation are corect represented by Green color*/ 154 public static final int CORRECT_TYPE = 1; 155 /** A partially correct type when all annotation are corect represented 156 * by Blue color*/ 157 public static final int PARTIALLY_CORRECT_TYPE = 2; 158 /** A spurious type when annotations in response were not present in key. 159 * Represented by Red color*/ 160 public static final int SPURIOUS_TYPE = 3; 161 /** A missing type when annotations in key were not present in response 162 * Represented by Yellow color*/ 163 public static final int MISSING_TYPE = 4; 164 165 /** Red used for SPURIOUS_TYPE*/ 166 private final Color RED = new Color(255,173,181); 167 /** Green used for CORRECT_TYPE*/ 168 private final Color GREEN = new Color(173,255,214); 169 /** White used for DEFAULT_TYPE*/ 170 private final Color WHITE = new Color(255,255,255); 171 /** Blue used for PARTIALLY_CORRECT_TYPE*/ 172 private final Color BLUE = new Color(173,215,255); 173 /** Yellow used for MISSING_TYPE*/ 174 private final Color YELLOW = new Color(255,231,173); 175 176 /** Used in DiffSetElement to represent an empty raw in the table*/ 177 private final int NULL_TYPE = -1; 178 /** Used in some setForeground() methods*/ 179 private final Color BLACK = new Color(0,0,0); 180 /** The array holding the colours according to the annotation types*/ 181 private Color colors[] = new Color[MAX_TYPES]; 182 183 /** A scroll for the AnnotDiff's table*/ 184 private JScrollPane scrollPane = null; 185 186 /** Used to store the no. of annotations from response,identified as belonging 187 * to one of the previous types. 188 */ 189 private int typeCounter[] = new int[MAX_TYPES]; 190 191 /** Constructs a CorpusAnnotationDiff*/ 192 public CorpusAnnotationDiff(){ 193 } //CorpusAnnotationDiff 194 195 /** Sets the annotation type needed to calculate the falsePossitive measure 196 * @param anAnnotType is the annotation type needed to calculate a special 197 * mesure called falsePossitive. Usualy the value is "token", but it can be 198 * any other string with the same semantic. 199 */ 200 public void setAnnotationTypeForFalsePositive(String anAnnotType){ 201 annotationTypeForFalsePositive = anAnnotType; 202 } // setAnnotationTypeForFalsePositive 203 204 /** Gets the annotation type needed to calculate the falsePossitive measure 205 * @return annotation type needed to calculate a special 206 * mesure called falsePossitive. 207 */ 208 public String getAnnotationTypeForFalsePositive(){ 209 return annotationTypeForFalsePositive; 210 } // getAnnotationTypeForFalsePositive 211 212 /** Sets the keyCorpus in AnnotDiff 213 * @param aKeyCorpus The GATE corpus used as a key in annotation diff. 214 */ 215 public void setKeyCorpus(Corpus aKeyCorpus) { 216 keyCorpus = aKeyCorpus; 217 } // setKeyCorpus 218 219 /** @return the keyCorpus used in AnnotDiff process */ 220 public Corpus getKeyCorpus(){ 221 return keyCorpus; 222 } // getKeyCorpus 223 224 /** Sets the keyAnnotationSetName in AnnotDiff 225 * @param aKeyAnnotationSetName The name of the annotation set from the 226 * keyDocument.If aKeyAnnotationSetName is null then the default annotation 227 * set will be used. 228 */ 229 public void setKeyAnnotationSetName(String aKeyAnnotationSetName){ 230 keyAnnotationSetName = aKeyAnnotationSetName; 231 } // setKeyAnnotationSetName(); 232 233 /** Gets the keyAnnotationSetName. 234 * @return The name of the keyAnnotationSet used in AnnotationDiff. If 235 * returns null then the the default annotation set will be used. 236 */ 237 public String getKeyAnnotationSetName(){ 238 return keyAnnotationSetName; 239 } // getKeyAnnotationSetName() 240 241 /** Sets the keyFeatureNamesSet in AnnotDiff. 242 * @param aKeyFeatureNamesSet a set containing the feature names from key 243 * that will be used in isPartiallyCompatible() 244 */ 245 public void setKeyFeatureNamesSet(Set aKeyFeatureNamesSet){ 246 keyFeatureNamesSet = aKeyFeatureNamesSet; 247 }//setKeyFeatureNamesSet(); 248 249 /** Gets the keyFeatureNamesSet in AnnotDiff. 250 * @return A set containing the feature names from key 251 * that will be used in isPartiallyCompatible() 252 */ 253 public Set getKeyFeatureNamesSet(){ 254 return keyFeatureNamesSet; 255 }//getKeyFeatureNamesSet(); 256 257 /** Sets the responseAnnotationSetName in AnnotDiff 258 * @param aResponseAnnotationSetName The name of the annotation set from the 259 * responseDocument.If aResponseAnnotationSetName is null then the default 260 * annotation set will be used. 261 */ 262 public void setResponseAnnotationSetName(String aResponseAnnotationSetName){ 263 responseAnnotationSetName = aResponseAnnotationSetName; 264 } // setResponseAnnotationSetName(); 265 266 /** gets the responseAnnotationSetName. 267 * @return The name of the responseAnnotationSet used in AnnotationDiff. If 268 * returns null then the the default annotation set will be used. 269 */ 270 public String getResponseAnnotationSetName(){ 271 return responseAnnotationSetName; 272 } // getResponseAnnotationSetName() 273 274 /** Sets the responseAnnotationSetNameFalsePoz in AnnotDiff 275 * @param aResponseAnnotationSetNameFalsePoz The name of the annotation set 276 * from the responseDocument.If aResponseAnnotationSetName is null 277 * then the default annotation set will be used. 278 */ 279 public void setResponseAnnotationSetNameFalsePoz( 280 String aResponseAnnotationSetNameFalsePoz){ 281 responseAnnotationSetNameFalsePoz = aResponseAnnotationSetNameFalsePoz; 282 } // setResponseAnnotationSetNameFalsePoz(); 283 284 /** gets the responseAnnotationSetNameFalsePoz. 285 * @return The name of the responseAnnotationSetFalsePoz used in 286 * AnnotationDiff. If returns null then the the default annotation 287 * set will be used. 288 */ 289 public String getResponseAnnotationSetNameFalsePoz(){ 290 return responseAnnotationSetNameFalsePoz; 291 } // getResponseAnnotationSetNamefalsePoz() 292 293 /** Sets the annot diff to work in the text mode.This would not initiate the 294 * GUI part of annot diff but it would calculate precision etc 295 */ 296 public void setTextMode(Boolean aTextMode){ 297 //it needs to be a Boolean and not boolean, because you cannot put 298 //in the parameters hashmap a boolean, it needs an object 299 textMode = aTextMode.booleanValue(); 300 }// End setTextMode(); 301 302 /** Gets the annot diff textmode.True means that the text mode is activated.*/ 303 public boolean isTextMode(){ 304 return textMode; 305 }// End setTextMode(); 306 307 /** Returns a set with all annotations of a specific type*/ 308 public Set getAnnotationsOfType(int annotType){ 309 HashSet results = new HashSet(); 310 if (diffSet == null) return results; 311 Iterator diffIter = diffSet.iterator(); 312 while(diffIter.hasNext()){ 313 DiffSetElement diffElem = (DiffSetElement)diffIter.next(); 314 switch(annotType){ 315 case CORRECT_TYPE:{ 316 if (diffElem.getRightType() == CORRECT_TYPE) 317 results.add(diffElem.getRightAnnotation()); 318 }break; 319 case PARTIALLY_CORRECT_TYPE:{ 320 if (diffElem.getRightType() == PARTIALLY_CORRECT_TYPE) 321 results.add(diffElem.getRightAnnotation()); 322 }break; 323 case SPURIOUS_TYPE:{ 324 if (diffElem.getRightType() == SPURIOUS_TYPE) 325 results.add(diffElem.getRightAnnotation()); 326 }break; 327 case MISSING_TYPE:{ 328 if (diffElem.getLeftType() == MISSING_TYPE) 329 results.add(diffElem.getLeftAnnotation()); 330 }break; 331 case DEFAULT_TYPE:{ 332 if (diffElem.getLeftType() == DEFAULT_TYPE) 333 results.add(diffElem.getLeftAnnotation()); 334 }break; 335 }// End switch 336 }// End while 337 return results; 338 }//getAnnotationsOfType 339 340 //Prameters utility methods 341 /** 342 * Gets the value of a parameter of this resource. 343 * @param paramaterName the name of the parameter 344 * @return the current value of the parameter 345 */ 346 public Object getParameterValue(String paramaterName) 347 throws ResourceInstantiationException{ 348 return AbstractResource.getParameterValue(this, paramaterName); 349 } 350 351 /** 352 * Sets the value for a specified parameter. 353 * 354 * @param paramaterName the name for the parameteer 355 * @param parameterValue the value the parameter will receive 356 */ 357 public void setParameterValue(String paramaterName, Object parameterValue) 358 throws ResourceInstantiationException{ 359 // get the beaninfo for the resource bean, excluding data about Object 360 BeanInfo resBeanInf = null; 361 try { 362 resBeanInf = Introspector.getBeanInfo(this.getClass(), Object.class); 363 } catch(Exception e) { 364 throw new ResourceInstantiationException( 365 "Couldn't get bean info for resource " + this.getClass().getName() 366 + Strings.getNl() + "Introspector exception was: " + e 367 ); 368 } 369 AbstractResource.setParameterValue(this, resBeanInf, paramaterName, parameterValue); 370 } 371 372 /** 373 * Sets the values for more parameters in one step. 374 * 375 * @param parameters a feature map that has paramete names as keys and 376 * parameter values as values. 377 */ 378 public void setParameterValues(FeatureMap parameters) 379 throws ResourceInstantiationException{ 380 AbstractResource.setParameterValues(this, parameters); 381 } 382 383 384 385 /////////////////////////////////////////////////// 386 // PRECISION methods 387 /////////////////////////////////////////////////// 388 389 /** @return the precisionStrict field*/ 390 public double getPrecisionStrict(){ 391 return precisionStrict; 392 } // getPrecisionStrict 393 394 /** @return the precisionLenient field*/ 395 public double getPrecisionLenient(){ 396 return precisionLenient; 397 } // getPrecisionLenient 398 399 /** @return the precisionAverage field*/ 400 public double getPrecisionAverage(){ 401 return precisionAverage; 402 } // getPrecisionAverage 403 404 /** @return the fMeasureStrict field*/ 405 public double getFMeasureStrict(){ 406 return fMeasureStrict; 407 } // getFMeasureStrict 408 409 /** @return the fMeasureLenient field*/ 410 public double getFMeasureLenient(){ 411 return fMeasureLenient; 412 } // getFMeasureLenient 413 414 /** @return the fMeasureAverage field*/ 415 public double getFMeasureAverage(){ 416 return fMeasureAverage; 417 } // getFMeasureAverage 418 419 /////////////////////////////////////////////////// 420 // RECALL methods 421 /////////////////////////////////////////////////// 422 423 /** @return the recallStrict field*/ 424 public double getRecallStrict(){ 425 return recallStrict; 426 } // getRecallStrict 427 428 /** @return the recallLenient field*/ 429 public double getRecallLenient(){ 430 return recallLenient; 431 } // getRecallLenient 432 433 /** @return the recallAverage field*/ 434 public double getRecallAverage(){ 435 return recallAverage; 436 } // getRecallAverage 437 438 /////////////////////////////////////////////////// 439 // FALSE POSITIVE methods 440 /////////////////////////////////////////////////// 441 442 /** @return the falsePositiveStrict field*/ 443 public double getFalsePositiveStrict(){ 444 return falsePositiveStrict; 445 } // getFalsePositiveStrict 446 447 /** @return the falsePositiveLenient field*/ 448 public double getFalsePositiveLenient(){ 449 return falsePositiveLenient; 450 } // getFalsePositiveLenient 451 452 /** @return the falsePositiveAverage field*/ 453 public double getFalsePositiveAverage(){ 454 return falsePositiveAverage; 455 } // getFalsePositive 456 457 /** 458 * @param aResponseCorpus the GATE response corpus 459 * containing the annotation Set being compared against the annotation from 460 * the keyCorpus. 461 */ 462 public void setResponseCorpus(Corpus aResponseCorpus) { 463 responseCorpus = aResponseCorpus; 464 } //setResponseCorpus 465 466 /** 467 * @param anAnnotationSchema the annotation type being compared. 468 * This type is found in annotationSchema object as field 469 * {@link gate.creole.AnnotationSchema#getAnnotationName()}. If is <b>null<b> 470 * then AnnotDiff will throw an exception when it comes to do the diff. 471 */ 472 public void setAnnotationSchema(AnnotationSchema anAnnotationSchema) { 473 annotationSchema = anAnnotationSchema; 474 } // setAnnotationType 475 476 /** @return the annotation schema object used in annotation diff process */ 477 public AnnotationSchema getAnnotationSchema(){ 478 return annotationSchema; 479 } // AnnotationSchema 480 481 public Dimension getPreferredScrollableViewportSize() { 482 return getPreferredSize(); 483 }// public Dimension getPreferredScrollableViewportSize() 484 485 public int getScrollableUnitIncrement(Rectangle visibleRect, 486 int orientation, int direction) { 487 return maxUnitIncrement; 488 }// public int getScrollableUnitIncrement 489 490 public int getScrollableBlockIncrement(Rectangle visibleRect, 491 int orientation, int direction) { 492 if (orientation == SwingConstants.HORIZONTAL) 493 return visibleRect.width - maxUnitIncrement; 494 else 495 return visibleRect.height - maxUnitIncrement; 496 }// public int getScrollableBlockIncrement 497 498 public boolean getScrollableTracksViewportWidth() { 499 return false; 500 }// public boolean getScrollableTracksViewportWidth() 501 502 public boolean getScrollableTracksViewportHeight() { 503 return false; 504 } 505 506 /** 507 * This method does the diff, Precision,Recall,FalsePositive 508 * calculation and so on. 509 */ 510 public Resource init() throws ResourceInstantiationException { 511 colors[DEFAULT_TYPE] = WHITE; 512 colors[CORRECT_TYPE] = GREEN; 513 colors[SPURIOUS_TYPE] = RED; 514 colors[PARTIALLY_CORRECT_TYPE] = BLUE; 515 colors[MISSING_TYPE] = YELLOW; 516 517 // Initialize the partially sets... 518 keyPartiallySet = new HashSet(); 519 responsePartiallySet = new HashSet(); 520 521 // Do the diff, P&R calculation and so on 522 AnnotationSet keyAnnotSet = null; 523 AnnotationSet responseAnnotSet = null; 524 525 if(annotationSchema == null) 526 throw new ResourceInstantiationException("No annotation schema defined !"); 527 528 if(keyCorpus == null || 0 == keyCorpus.size()) 529 throw new ResourceInstantiationException("No key corpus or empty defined !"); 530 531 if(responseCorpus == null || 0 == responseCorpus.size()) 532 throw new ResourceInstantiationException("No response corpus or empty defined !"); 533 534 // init counters and do difference for documents by pairs 535 for (int type=0; type < MAX_TYPES; type++) 536 typeCounter[type] = 0; 537 diffSet = new HashSet(); 538 539 for(int i=0; i<keyCorpus.size(); ++i) { 540 keyDocument = (Document) keyCorpus.get(i); 541 // find corresponding responce document if any 542 543 Document doc; 544 responseDocument = null; 545 for(int j=0; j<responseCorpus.size(); ++j) { 546 doc = (Document) responseCorpus.get(j); 547 if(0 == doc.getName().compareTo(keyDocument.getName()) 548 || 0 == doc.getSourceUrl().getFile().compareTo( 549 keyDocument.getSourceUrl().getFile())) { 550 responseDocument = doc; 551 break; // response corpus loop 552 } // if 553 } // for 554 555 if(null == responseDocument) { 556 Out.prln("There is no mach in responce corpus for document '" 557 +keyDocument.getName()+"' from key corpus"); 558 continue; // key corpus loop 559 } // if 560 561 if (keyAnnotationSetName == null) { 562 // Get the default key AnnotationSet from the keyDocument 563 keyAnnotSet = keyDocument.getAnnotations().get( 564 annotationSchema.getAnnotationName()); 565 } 566 else { 567 keyAnnotSet = keyDocument.getAnnotations(keyAnnotationSetName).get( 568 annotationSchema.getAnnotationName()); 569 } // if 570 571 if (keyAnnotSet == null) 572 // The diff will run with an empty set.All annotations from response 573 // would be spurious. 574 keyAnnotList = new LinkedList(); 575 else 576 // The alghoritm will modify this annotation set. It is better to make a 577 // separate copy of them. 578 keyAnnotList = new LinkedList(keyAnnotSet); 579 580 if (responseAnnotationSetName == null) 581 // Get the response AnnotationSet from the default set 582 responseAnnotSet = responseDocument.getAnnotations().get( 583 annotationSchema.getAnnotationName()); 584 else 585 responseAnnotSet = responseDocument.getAnnotations(responseAnnotationSetName). 586 get(annotationSchema.getAnnotationName()); 587 588 if (responseAnnotSet == null) 589 // The diff will run with an empty set.All annotations from key 590 // would be missing. 591 responseAnnotList = new LinkedList(); 592 else 593 // The alghoritm will modify this annotation set. It is better to make a 594 // separate copy of them. 595 responseAnnotList = new LinkedList(responseAnnotSet); 596 597 // Sort them ascending on Start offset (the comparator does that) 598 AnnotationSetComparator asComparator = new AnnotationSetComparator(); 599 Collections.sort(keyAnnotList, asComparator); 600 Collections.sort(responseAnnotList, asComparator); 601 602 // Calculate the diff Set. This set will be used later with graphic 603 // visualisation. 604 doDiff(keyAnnotList, responseAnnotList); 605 } // for 606 607 // If it runs under text mode just stop here. 608 if (textMode) return this; 609 610 //Show it 611 // Configuring the formatter object. It will be used later to format 612 // precision and recall 613 formatter.setMaximumIntegerDigits(1); 614 formatter.setMinimumFractionDigits(4); 615 formatter.setMinimumFractionDigits(4); 616 617 // Create an Annotation diff table model 618 AnnotationDiffTableModel diffModel = new AnnotationDiffTableModel(diffSet); 619 // Create a XJTable based on this model 620 diffTable = new XJTable(diffModel); 621 diffTable.setAlignmentX(Component.LEFT_ALIGNMENT); 622 // Set the cell renderer for this table. 623 AnnotationDiffCellRenderer cellRenderer = new AnnotationDiffCellRenderer(); 624 diffTable.setDefaultRenderer(java.lang.String.class,cellRenderer); 625 diffTable.setDefaultRenderer(java.lang.Long.class,cellRenderer); 626 // Put the table into a JScroll 627 628 // Arange all components on a this JPanel 629 SwingUtilities.invokeLater(new Runnable(){ 630 public void run(){ 631 arangeAllComponents(); 632 } 633 }); 634 635 if (DEBUG) 636 printStructure(diffSet); 637 638 return this; 639 } //init() 640 641 /** This method creates the graphic components and aranges them on 642 * <b>this</b> JPanel 643 */ 644 protected void arangeAllComponents(){ 645 this.removeAll(); 646 // Setting the box layout for diffpanel 647 BoxLayout boxLayout = new BoxLayout(this,BoxLayout.Y_AXIS); 648 this.setLayout(boxLayout); 649 650 JTableHeader tableHeader = diffTable.getTableHeader(); 651 tableHeader.setAlignmentX(Component.LEFT_ALIGNMENT); 652 this.add(tableHeader); 653 diffTable.setAlignmentX(Component.LEFT_ALIGNMENT); 654 // Add the tableScroll to the diffPanel 655 this.add(diffTable); 656 657 658 // ADD the LEGEND 659 //Lay out the JLabels from left to right. 660 //Box infoBox = new Box(BoxLayout.X_AXIS); 661 JPanel infoBox = new JPanel(); 662 infoBox.setLayout(new BoxLayout(infoBox,BoxLayout.X_AXIS)); 663 infoBox.setAlignmentX(Component.LEFT_ALIGNMENT); 664 // Keep the components together 665 //box.add(Box.createHorizontalGlue()); 666 667 Box box = new Box(BoxLayout.Y_AXIS); 668 JLabel jLabel = new JLabel("LEGEND"); 669 jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD)); 670 jLabel.setOpaque(true); 671 jLabel.setAlignmentX(Component.LEFT_ALIGNMENT); 672 box.add(jLabel); 673 674 jLabel = new JLabel("Missing (present in Key but not in Response): " + 675 typeCounter[MISSING_TYPE]); 676 jLabel.setForeground(BLACK); 677 jLabel.setBackground(colors[MISSING_TYPE]); 678 jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD)); 679 jLabel.setOpaque(true); 680 jLabel.setAlignmentX(Component.LEFT_ALIGNMENT); 681 box.add(jLabel); 682 683 // Add a space 684 box.add(Box.createRigidArea(new Dimension(0,5))); 685 686 jLabel = new JLabel("Correct (total match): " + typeCounter[CORRECT_TYPE]); 687 jLabel.setForeground(BLACK); 688 jLabel.setBackground(colors[CORRECT_TYPE]); 689 jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD)); 690 jLabel.setOpaque(true); 691 jLabel.setAlignmentX(Component.LEFT_ALIGNMENT); 692 box.add(jLabel); 693 694 // Add a space 695 box.add(Box.createRigidArea(new Dimension(0,5))); 696 697 jLabel =new JLabel("Partially correct (overlap in Key and Response): "+ 698 typeCounter[PARTIALLY_CORRECT_TYPE]); 699 jLabel.setForeground(BLACK); 700 jLabel.setBackground(colors[PARTIALLY_CORRECT_TYPE]); 701 jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD)); 702 jLabel.setOpaque(true); 703 jLabel.setAlignmentX(Component.LEFT_ALIGNMENT); 704 box.add(jLabel); 705 706 // Add a space 707 box.add(Box.createRigidArea(new Dimension(0,5))); 708 709 jLabel = new JLabel("Spurious (present in Response but not in Key): " + 710 typeCounter[SPURIOUS_TYPE]); 711 jLabel.setForeground(BLACK); 712 jLabel.setBackground(colors[SPURIOUS_TYPE]); 713 jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD)); 714 jLabel.setOpaque(true); 715 jLabel.setAlignmentX(Component.LEFT_ALIGNMENT); 716 box.add(jLabel); 717 718 infoBox.add(box); 719 // Add a space 720 infoBox.add(Box.createRigidArea(new Dimension(40,0))); 721 722 // Precision measure 723 //Lay out the JLabels from left to right. 724 box = new Box(BoxLayout.Y_AXIS); 725 726 jLabel = new JLabel("Precision strict: " + 727 formatter.format(precisionStrict)); 728 jLabel.setAlignmentX(Component.LEFT_ALIGNMENT); 729 jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD)); 730 box.add(jLabel); 731 732 jLabel = new JLabel("Precision average: " + 733 formatter.format(precisionAverage)); 734 jLabel.setAlignmentX(Component.LEFT_ALIGNMENT); 735 jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD)); 736 box.add(jLabel); 737 738 jLabel = new JLabel("Precision lenient: " + 739 formatter.format(precisionLenient)); 740 jLabel.setAlignmentX(Component.LEFT_ALIGNMENT); 741 jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD)); 742 box.add(jLabel); 743 744 infoBox.add(box); 745 // Add a space 746 infoBox.add(Box.createRigidArea(new Dimension(40,0))); 747 748 // RECALL measure 749 //Lay out the JLabels from left to right. 750 box = new Box(BoxLayout.Y_AXIS); 751 752 jLabel = new JLabel("Recall strict: " + formatter.format(recallStrict)); 753 jLabel.setAlignmentX(Component.LEFT_ALIGNMENT); 754 jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD)); 755 box.add(jLabel); 756 757 jLabel = new JLabel("Recall average: " + formatter.format(recallAverage)); 758 jLabel.setAlignmentX(Component.LEFT_ALIGNMENT); 759 jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD)); 760 box.add(jLabel); 761 762 jLabel = new JLabel("Recall lenient: " + formatter.format(recallLenient)); 763 jLabel.setAlignmentX(Component.LEFT_ALIGNMENT); 764 jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD)); 765 box.add(jLabel); 766 767 infoBox.add(box); 768 // Add a space 769 infoBox.add(Box.createRigidArea(new Dimension(40,0))); 770 771 // F-Measure 772 //Lay out the JLabels from left to right. 773 box = new Box(BoxLayout.Y_AXIS); 774 775 jLabel = new JLabel("F-Measure strict: " + 776 formatter.format(fMeasureStrict)); 777 jLabel.setAlignmentX(Component.LEFT_ALIGNMENT); 778 jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD)); 779 box.add(jLabel); 780 781 jLabel = new JLabel("F-Measure average: " + 782 formatter.format(fMeasureAverage)); 783 jLabel.setAlignmentX(Component.LEFT_ALIGNMENT); 784 jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD)); 785 box.add(jLabel); 786 787 jLabel = new JLabel("F-Measure lenient: " + 788 formatter.format(fMeasureLenient)); 789 jLabel.setAlignmentX(Component.LEFT_ALIGNMENT); 790 jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD)); 791 box.add(jLabel); 792 infoBox.add(box); 793 794 // Add a space 795 infoBox.add(Box.createRigidArea(new Dimension(40,0))); 796 797 // FALSE POZITIVE measure 798 //Lay out the JLabels from left to right. 799 box = new Box(BoxLayout.Y_AXIS); 800 801 jLabel = new JLabel("False positive strict: " + 802 formatter.format(falsePositiveStrict)); 803 jLabel.setAlignmentX(Component.LEFT_ALIGNMENT); 804 jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD)); 805 box.add(jLabel); 806 807 jLabel = new JLabel("False positive average: " + 808 formatter.format(falsePositiveAverage)); 809 jLabel.setAlignmentX(Component.LEFT_ALIGNMENT); 810 jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD)); 811 box.add(jLabel); 812 813 jLabel = new JLabel("False positive lenient: " + 814 formatter.format(falsePositiveLenient)); 815 jLabel.setAlignmentX(Component.LEFT_ALIGNMENT); 816 jLabel.setFont(jLabel.getFont().deriveFont(Font.BOLD)); 817 box.add(jLabel); 818 infoBox.add(box); 819 820 // Add a space 821 infoBox.add(Box.createRigidArea(new Dimension(10,0))); 822 823 this.add(infoBox); 824 } //arangeAllComponents 825 826 /** Used internally for debugging */ 827 protected void printStructure(Set aDiffSet){ 828 Iterator iterator = aDiffSet.iterator(); 829 String leftAnnot = null; 830 String rightAnnot = null; 831 while(iterator.hasNext()){ 832 DiffSetElement diffElem = (DiffSetElement) iterator.next(); 833 if (diffElem.getLeftAnnotation() == null) 834 leftAnnot = "NULL "; 835 else 836 leftAnnot = diffElem.getLeftAnnotation().toString(); 837 if (diffElem.getRightAnnotation() == null) 838 rightAnnot = " NULL"; 839 else 840 rightAnnot = diffElem.getRightAnnotation().toString(); 841 Out.prln( leftAnnot + "|" + rightAnnot); 842 } // end while 843 } // printStructure 844 845 /** This method is the brain of the AnnotationSet diff and creates a set with 846 * diffSetElement objects. 847 * @param aKeyAnnotList a list containing the annotations from key. If this 848 * param is <b>null</b> then the method will simply return and will not do a 849 * thing. 850 * @param aResponseAnnotList a list containing the annotation from response. 851 * If this param is <b>null</b> the method will return. 852 */ 853 protected void doDiff(java.util.List aKeyAnnotList, 854 java.util.List aResponseAnnotList){ 855 856 // If one of the annotation sets is null then is no point in doing the diff. 857 if (aKeyAnnotList == null || aResponseAnnotList == null) 858 return; 859 860 int responseSize = aResponseAnnotList.size(); 861 862 // Iterate throught all elements from keyList and find those in the response 863 // list which satisfies isCompatible() and isPartiallyCompatible() relations 864 Iterator keyIterator = aKeyAnnotList.iterator(); 865 while(keyIterator.hasNext()){ 866 Annotation keyAnnot = (Annotation) keyIterator.next(); 867 Iterator responseIterator = aResponseAnnotList.iterator(); 868 869 DiffSetElement diffElement = null; 870 while(responseIterator.hasNext()){ 871 Annotation responseAnnot = (Annotation) responseIterator.next(); 872 873 if(keyAnnot.isPartiallyCompatible(responseAnnot,keyFeatureNamesSet)){ 874 keyPartiallySet.add(keyAnnot); 875 responsePartiallySet.add(responseAnnot); 876 if (keyAnnot.coextensive(responseAnnot)){ 877 // Found two compatible annotations 878 // Create a new DiffSetElement and add it to the diffSet 879 diffElement = new DiffSetElement( keyAnnot, 880 responseAnnot, 881 DEFAULT_TYPE, 882 CORRECT_TYPE, 883 keyDocument, 884 responseDocument); 885 886 // Add this element to the DiffSet 887 addToDiffset(diffElement); 888 } // End if (keyAnnot.coextensive(responseAnnot)) 889 }else if (keyAnnot.coextensive(responseAnnot)){ 890 // Found two aligned annotations. We have to find out if the response 891 // is partialy compatible with another key annotation. 892 // Create a new DiffSetElement and add it to the diffSet 893 diffElement = new DiffSetElement( keyAnnot, 894 responseAnnot, 895 detectKeyType(keyAnnot), 896 detectResponseType(responseAnnot), 897 keyDocument, 898 responseDocument); 899 // Add this element to the DiffSet 900 addToDiffset(diffElement); 901 } // End if (keyAnnot.coextensive(responseAnnot)){ 902 903 if (diffElement != null){ 904 // Eliminate the response annotation from the list. 905 responseIterator.remove(); 906 break; 907 } // End if 908 } // end while responseIterator 909 910 // If diffElement != null it means that break was used 911 if (diffElement == null){ 912 if (keyPartiallySet.contains(keyAnnot)) 913 diffElement = new DiffSetElement( keyAnnot, 914 null, 915 DEFAULT_TYPE, 916 NULL_TYPE, 917 keyDocument, 918 responseDocument); 919 else{ 920 // If keyAnnot is not in keyPartiallySet then it has to be checked 921 // agains all annotations in DiffSet to see if there is 922 // a previous annotation from response set which is partially 923 // compatible with the keyAnnot 924 Iterator respParIter = diffSet.iterator(); 925 while (respParIter.hasNext()){ 926 DiffSetElement diffElem = (DiffSetElement) respParIter.next(); 927 Annotation respAnnot = diffElem.getRightAnnotation(); 928 if (respAnnot != null && keyAnnot.isPartiallyCompatible(respAnnot, 929 keyFeatureNamesSet)){ 930 diffElement = new DiffSetElement( keyAnnot, 931 null, 932 DEFAULT_TYPE, 933 NULL_TYPE, 934 keyDocument, 935 responseDocument); 936 break; 937 } // End if 938 } // End while 939 // If is still nul then it means that the key annotation is missing 940 if (diffElement == null) 941 diffElement = new DiffSetElement( keyAnnot, 942 null, 943 MISSING_TYPE, 944 NULL_TYPE, 945 keyDocument, 946 responseDocument); 947 } // End if 948 addToDiffset(diffElement); 949 } // End if 950 951 keyIterator.remove(); 952 } // end while keyIterator 953 954 DiffSetElement diffElem = null; 955 Iterator responseIter = aResponseAnnotList.iterator(); 956 while (responseIter.hasNext()){ 957 Annotation respAnnot = (Annotation) responseIter.next(); 958 if (responsePartiallySet.contains(respAnnot)) 959 diffElem = new DiffSetElement( null, 960 respAnnot, 961 NULL_TYPE, 962 PARTIALLY_CORRECT_TYPE, 963 keyDocument, 964 responseDocument); 965 else 966 diffElem = new DiffSetElement( null, 967 respAnnot, 968 NULL_TYPE, 969 SPURIOUS_TYPE, 970 keyDocument, 971 responseDocument); 972 addToDiffset(diffElem); 973 responseIter.remove(); 974 } // End while 975 976 // CALCULATE ALL (NLP) MEASURES like: 977 // Precistion, Recall, FalsePositive and F-Measure 978 int possible = typeCounter[CORRECT_TYPE] + // this comes from Key or Resp 979 typeCounter[PARTIALLY_CORRECT_TYPE] + // this comes from Resp 980 typeCounter[MISSING_TYPE]; // this comes from Key 981 982 int actual = typeCounter[CORRECT_TYPE] + // this comes from Key or Resp 983 typeCounter[PARTIALLY_CORRECT_TYPE] + // this comes from Resp 984 typeCounter[SPURIOUS_TYPE]; // this comes from Resp 985 /* 986 if (actual != responseSize) 987 Err.prln("AnnotDiff warning: The response size(" + responseSize + 988 ") is not the same as the computed value of" + 989 " actual(Correct[resp or key]+Partial[resp]+Spurious[resp]=" + actual +")"); 990 */ 991 if (actual != 0){ 992 precisionStrict = ((double)typeCounter[CORRECT_TYPE])/((double)actual); 993 precisionLenient = ((double)(typeCounter[CORRECT_TYPE] + 994 typeCounter[PARTIALLY_CORRECT_TYPE]))/((double)actual); 995 precisionAverage = ((double)(precisionStrict + precisionLenient)) / 996 ((double) 2); 997 } // End if 998 if (possible != 0){ 999 recallStrict = ((double)typeCounter[CORRECT_TYPE])/((double)possible); 1000 recallLenient = ((double)(typeCounter[CORRECT_TYPE] + 1001 typeCounter[PARTIALLY_CORRECT_TYPE]))/((double)possible); 1002 recallAverage = ((double)(recallStrict + recallLenient)) / ((double)2); 1003 } // End if 1004 1005 1006 int no = 0; 1007 // If an annotation type for false poz was selected calculate the number of 1008 // Annotations 1009 if (annotationTypeForFalsePositive != null) 1010 // Was it the default set ? 1011 if (responseAnnotationSetNameFalsePoz == null){ 1012 AnnotationSet aSet = responseDocument.getAnnotations().get( 1013 annotationTypeForFalsePositive); 1014 no = aSet == null ? 0 : aSet.size(); 1015 }else{ 1016 AnnotationSet aSet = responseDocument.getAnnotations(responseAnnotationSetNameFalsePoz).get( 1017 annotationTypeForFalsePositive); 1018 no = aSet == null? 0 : aSet.size(); 1019 } 1020 if (no != 0){ 1021 // No error here: the formula is the opposite to recall or precission 1022 falsePositiveStrict = ((double)(typeCounter[SPURIOUS_TYPE] + 1023 typeCounter[PARTIALLY_CORRECT_TYPE])) /((double)no); 1024 falsePositiveLenient = ((double)typeCounter[SPURIOUS_TYPE]) /((double) no); 1025 falsePositiveAverage = ((double)(falsePositiveStrict + 1026 falsePositiveLenient))/((double)2) ; 1027 } // End if 1028 1029 // Calculate F-Measure Strict 1030 double denominator = weight * (precisionStrict + recallStrict); 1031 if (denominator != 0) 1032 fMeasureStrict = (precisionStrict * recallStrict) / denominator ; 1033 else fMeasureStrict = 0.0; 1034 // Calculate F-Measure Lenient 1035 denominator = weight * (precisionLenient + recallLenient); 1036 if (denominator != 0) 1037 fMeasureLenient = (precisionLenient * recallLenient) / denominator ; 1038 else fMeasureLenient = 0.0; 1039 // Calculate F-Measure Average 1040 fMeasureAverage = (fMeasureStrict + fMeasureLenient) / (double)2; 1041 1042 } // doDiff 1043 1044 /** Decide what type is the keyAnnotation (DEFAULT_TYPE, MISSING or NULL_TYPE) 1045 * This method must be applied only on annotation from key set. 1046 * @param anAnnot is an annotation from the key set. 1047 * @return three possible value(DEFAULT_TYPE, MISSING or NULL_TYPE) 1048 */ 1049 private int detectKeyType(Annotation anAnnot){ 1050 if (anAnnot == null) return NULL_TYPE; 1051 1052 if (keyPartiallySet.contains(anAnnot)) return DEFAULT_TYPE; 1053 Iterator iter = responsePartiallySet.iterator(); 1054 while(iter.hasNext()){ 1055 Annotation a = (Annotation) iter.next(); 1056 if (anAnnot.isPartiallyCompatible(a,keyFeatureNamesSet)) 1057 return DEFAULT_TYPE; 1058 } // End while 1059 1060 iter = responseAnnotList.iterator(); 1061 while(iter.hasNext()){ 1062 Annotation a = (Annotation) iter.next(); 1063 if (anAnnot.isPartiallyCompatible(a,keyFeatureNamesSet)){ 1064 responsePartiallySet.add(a); 1065 keyPartiallySet.add(anAnnot); 1066 return DEFAULT_TYPE; 1067 } // End if 1068 } // End while 1069 return MISSING_TYPE; 1070 } //detectKeyType 1071 1072 /** Decide what type is the responseAnnotation 1073 * (PARTIALLY_CORRECT_TYPE, SPURIOUS or NULL_TYPE) 1074 * This method must be applied only on annotation from response set. 1075 * @param anAnnot is an annotation from the key set. 1076 * @return three possible value(PARTIALLY_CORRECT_TYPE, SPURIOUS or NULL_TYPE) 1077 */ 1078 private int detectResponseType(Annotation anAnnot){ 1079 if (anAnnot == null) return NULL_TYPE; 1080 1081 if (responsePartiallySet.contains(anAnnot)) return PARTIALLY_CORRECT_TYPE; 1082 Iterator iter = keyPartiallySet.iterator(); 1083 while(iter.hasNext()){ 1084 Annotation a = (Annotation) iter.next(); 1085 if (a.isPartiallyCompatible(anAnnot,keyFeatureNamesSet)) 1086 return PARTIALLY_CORRECT_TYPE; 1087 } // End while 1088 1089 iter = keyAnnotList.iterator(); 1090 while(iter.hasNext()){ 1091 Annotation a = (Annotation) iter.next(); 1092 if (a.isPartiallyCompatible(anAnnot,keyFeatureNamesSet)){ 1093 responsePartiallySet.add(anAnnot); 1094 keyPartiallySet.add(a); 1095 return PARTIALLY_CORRECT_TYPE; 1096 } // End if 1097 } // End while 1098 return SPURIOUS_TYPE; 1099 } //detectResponseType 1100 1101 /** This method add an DiffsetElement to the DiffSet and also counts the 1102 * number of compatible, partialCompatible, Incorect and Missing annotations. 1103 */ 1104 private void addToDiffset(DiffSetElement aDiffSetElement){ 1105 if (aDiffSetElement == null) return; 1106 1107 diffSet.add(aDiffSetElement); 1108 // For the Right side (response) the type can be one of the following: 1109 // PC, I, C 1110 if (NULL_TYPE != aDiffSetElement.getRightType()) 1111 typeCounter[aDiffSetElement.getRightType()]++; 1112 // For the left side (key) the type can be : D or M 1113 if (NULL_TYPE != aDiffSetElement.getLeftType() && 1114 CORRECT_TYPE != aDiffSetElement.getLeftType()) 1115 typeCounter[aDiffSetElement.getLeftType()]++; 1116 } // addToDiffset 1117 1118 /* ******************************************************************** 1119 * INNER CLASS 1120 * ********************************************************************/ 1121 1122 /** 1123 * A custom table model used to render a table containing the two annotation 1124 * sets. The columns will be: 1125 * (KEY) Type, Start, End, Features, empty column,(Response) Type,Start, End, Features 1126 */ 1127 protected class AnnotationDiffTableModel extends AbstractTableModel{ 1128 1129 /** Constructs an AnnotationDiffTableModel given a data Collection */ 1130 public AnnotationDiffTableModel(Collection data){ 1131 modelData = new ArrayList(); 1132 modelData.addAll(data); 1133 } // AnnotationDiffTableModel 1134 1135 /** Constructs an AnnotationDiffTableModel */ 1136 public AnnotationDiffTableModel(){ 1137 modelData = new ArrayList(); 1138 } // AnnotationDiffTableModel 1139 1140 /** Return the size of data.*/ 1141 public int getRowCount(){ 1142 return modelData.size(); 1143 } //getRowCount 1144 1145 /** Return the number of columns.*/ 1146 public int getColumnCount(){ 1147 return 10; 1148 } //getColumnCount 1149 1150 /** Returns the name of each column in the model*/ 1151 public String getColumnName(int column){ 1152 switch(column){ 1153 case 0: return "String - Key"; 1154 case 1: return "Start - Key"; 1155 case 2: return "End - Key"; 1156 case 3: return "Features - Key"; 1157 case 4: return " "; 1158 case 5: return "String - Response"; 1159 case 6: return "Start - Response"; 1160 case 7: return "End -Response"; 1161 case 8: return "Features - Response"; 1162 case 9: return "Document"; 1163 default:return "?"; 1164 } 1165 } //getColumnName 1166 1167 /** Return the class type for each column. */ 1168 public Class getColumnClass(int column){ 1169 switch(column){ 1170 case 0: return String.class; 1171 case 1: return Long.class; 1172 case 2: return Long.class; 1173 case 3: return String.class; 1174 case 4: return String.class; 1175 case 5: return String.class; 1176 case 6: return Long.class; 1177 case 7: return Long.class; 1178 case 8: return String.class; 1179 case 9: return String.class; 1180 default:return Object.class; 1181 } 1182 } //getColumnClass 1183 1184 /**Returns a value from the table model */ 1185 public Object getValueAt(int row, int column){ 1186 DiffSetElement diffSetElement = (DiffSetElement) modelData.get(row); 1187 if (diffSetElement == null) return null; 1188 switch(column){ 1189 // Left Side (Key) 1190 //Type - Key 1191 case 0:{ 1192 if (diffSetElement.getLeftAnnotation() == null) return null; 1193// return diffSetElement.getLeftAnnotation().getType(); 1194 Annotation annot = diffSetElement.getLeftAnnotation(); 1195 String theString = ""; 1196 try { 1197 theString = diffSetElement.getKeyDocument().getContent().getContent( 1198 annot.getStartNode().getOffset(), 1199 annot.getEndNode().getOffset()).toString(); 1200 } catch (gate.util.InvalidOffsetException ex) { 1201 Err.prln(ex.getMessage()); 1202 } 1203 return theString; 1204 } 1205 // Start - Key 1206 case 1:{ 1207 if (diffSetElement.getLeftAnnotation() == null) return null; 1208 return diffSetElement.getLeftAnnotation().getStartNode().getOffset(); 1209 } 1210 // End - Key 1211 case 2:{ 1212 if (diffSetElement.getLeftAnnotation() == null) return null; 1213 return diffSetElement.getLeftAnnotation().getEndNode().getOffset(); 1214 } 1215 // Features - Key 1216 case 3:{ 1217 if (diffSetElement.getLeftAnnotation() == null) return null; 1218 if (diffSetElement.getLeftAnnotation().getFeatures() == null) 1219 return null; 1220 return diffSetElement.getLeftAnnotation().getFeatures().toString(); 1221 } 1222 // Empty column 1223 case 4:{ 1224 return " "; 1225 } 1226 // Right Side (Response) 1227 //Type - Response 1228 case 5:{ 1229 if (diffSetElement.getRightAnnotation() == null) return null; 1230// return diffSetElement.getRightAnnotation().getType(); 1231 Annotation annot = diffSetElement.getRightAnnotation(); 1232 String theString = ""; 1233 try { 1234 theString = diffSetElement.getResponseDocument().getContent().getContent( 1235 annot.getStartNode().getOffset(), 1236 annot.getEndNode().getOffset()).toString(); 1237 } catch (gate.util.InvalidOffsetException ex) { 1238 Err.prln(ex.getMessage()); 1239 } 1240 return theString; 1241 } 1242 // Start - Response 1243 case 6:{ 1244 if (diffSetElement.getRightAnnotation() == null) return null; 1245 return diffSetElement.getRightAnnotation().getStartNode().getOffset(); 1246 } 1247 // End - Response 1248 case 7:{ 1249 if (diffSetElement.getRightAnnotation() == null) return null; 1250 return diffSetElement.getRightAnnotation().getEndNode().getOffset(); 1251 } 1252 // Features - resonse 1253 case 8:{ 1254 if (diffSetElement.getRightAnnotation() == null) return null; 1255 return diffSetElement.getRightAnnotation().getFeatures().toString(); 1256 } 1257 // Document name 1258 case 9:{ 1259 return diffSetElement.getKeyDocument().getName(); 1260 } 1261 // The hidden column 1262 case 10:{ 1263 return diffSetElement; 1264 } 1265 default:{return null;} 1266 } // End switch 1267 } //getValueAt 1268 1269 public Object getRawObject(int row){ 1270 return modelData.get(row); 1271 } //getRawObject 1272 1273 /** Holds the data for TableDiff*/ 1274 private java.util.List modelData = null; 1275 1276 } //Inner class AnnotationDiffTableModel 1277 1278 /* ******************************************************************** 1279 * INNER CLASS 1280 * ********************************************************************/ 1281 /** 1282 * This class defines a Cell renderer for the AnnotationDiff table 1283 */ 1284 public class AnnotationDiffCellRenderer extends DefaultTableCellRenderer{ 1285 1286 /** Constructs a randerer with a table model*/ 1287 public AnnotationDiffCellRenderer() { } //AnnotationDiffCellRenderer 1288 1289 private Color background = WHITE; 1290 1291 private Color foreground = BLACK; 1292 1293 /** This method is called by JTable*/ 1294 1295 public Component getTableCellRendererComponent( 1296 JTable table, Object value, boolean isSelected, boolean hasFocus, 1297 int row, int column 1298 ) { 1299 JComponent defaultComp = null; 1300 defaultComp = (JComponent) super.getTableCellRendererComponent( 1301 table, value, isSelected, hasFocus, row, column 1302 ); 1303 1304 // The column number four will be randered using a blank component 1305 if (column == 4 || value == null) 1306 return new JPanel(); 1307 1308 if (!(table.getModel().getValueAt(row,10) instanceof DiffSetElement)) 1309 return defaultComp; 1310 1311 DiffSetElement diffSetElement = 1312 (DiffSetElement) table.getModel().getValueAt(row,10); 1313 1314 if (diffSetElement == null) 1315 return defaultComp; 1316 1317 if (column < 4){ 1318 if (NULL_TYPE != diffSetElement.getLeftType()) 1319 background = colors[diffSetElement.getLeftType()]; 1320 else return new JPanel(); 1321 }else if (column < 10){ 1322 if (NULL_TYPE != diffSetElement.getRightType()) 1323 background = colors[diffSetElement.getRightType()]; 1324 else return new JPanel(); 1325 } 1326 1327 defaultComp.setBackground(background); 1328 defaultComp.setForeground(BLACK); 1329 1330 defaultComp.setOpaque(true); 1331 return defaultComp; 1332 } //getTableCellRendererComponent 1333 1334 } // class AnnotationDiffCellRenderer 1335 1336 /* ******************************************************************** 1337 * INNER CLASS 1338 * ********************************************************************/ 1339 class AnnotationSetComparator implements java.util.Comparator { 1340 1341 public AnnotationSetComparator(){} 1342 1343 public int compare(Object o1, Object o2) { 1344 if ( !(o1 instanceof gate.Annotation) || 1345 !(o2 instanceof gate.Annotation)) return 0; 1346 1347 gate.Annotation a1 = (gate.Annotation) o1; 1348 gate.Annotation a2 = (gate.Annotation) o2; 1349 1350 Long l1 = a1.getStartNode().getOffset(); 1351 Long l2 = a2.getStartNode().getOffset(); 1352 if (l1 != null) 1353 return l1.compareTo(l2); 1354 else 1355 return -1; 1356 } //compare 1357 } // class AnnotationSetComparator 1358 1359 /* ******************************************************************** 1360 * INNER CLASS 1361 * ********************************************************************/ 1362 1363 /** 1364 * This class is used for internal purposes. It represents a row from the 1365 * table. 1366 */ 1367 protected class DiffSetElement { 1368 /** This field represent a key annotation*/ 1369 private Annotation leftAnnotation = null; 1370 /** This field represent a response annotation*/ 1371 private Annotation rightAnnotation = null; 1372 /** Default initialization of the key type*/ 1373 private int leftType = DEFAULT_TYPE; 1374 /** Default initialization of the response type*/ 1375 private int rightType = DEFAULT_TYPE; 1376 /** Key document */ 1377 private Document keyDocument; 1378 /** Response document */ 1379 private Document respDocument; 1380 1381 /** Constructor for DiffSetlement*/ 1382 public DiffSetElement() {} 1383 1384 /** Constructor for DiffSetlement*/ 1385 public DiffSetElement( Annotation aLeftAnnotation, 1386 Annotation aRightAnnotation, 1387 int aLeftType, 1388 int aRightType){ 1389 leftAnnotation = aLeftAnnotation; 1390 rightAnnotation = aRightAnnotation; 1391 leftType = aLeftType; 1392 rightType = aRightType; 1393 keyDocument = null; 1394 respDocument = null; 1395 } // DiffSetElement 1396 1397 /** Constructor for DiffSetlement with document name */ 1398 public DiffSetElement( Annotation aLeftAnnotation, 1399 Annotation aRightAnnotation, 1400 int aLeftType, 1401 int aRightType, 1402 Document kDocument, 1403 Document rDocument){ 1404 leftAnnotation = aLeftAnnotation; 1405 rightAnnotation = aRightAnnotation; 1406 leftType = aLeftType; 1407 rightType = aRightType; 1408 keyDocument = kDocument; 1409 respDocument = rDocument; 1410 } // DiffSetElement 1411 1412 /** Sets the left annotation*/ 1413 public void setLeftAnnotation(Annotation aLeftAnnotation){ 1414 leftAnnotation = aLeftAnnotation; 1415 } // setLeftAnnot 1416 1417 /** Gets the left annotation*/ 1418 public Annotation getLeftAnnotation(){ 1419 return leftAnnotation; 1420 } // getLeftAnnotation 1421 1422 /** Sets the right annotation*/ 1423 public void setRightAnnotation(Annotation aRightAnnotation){ 1424 rightAnnotation = aRightAnnotation; 1425 } // setRightAnnot 1426 1427 /** Gets the right annotation*/ 1428 public Annotation getRightAnnotation(){ 1429 return rightAnnotation; 1430 } // getRightAnnotation 1431 1432 /** Sets the left type*/ 1433 public void setLeftType(int aLeftType){ 1434 leftType = aLeftType; 1435 } // setLeftType 1436 1437 /** Get the left type */ 1438 public int getLeftType() { 1439 return leftType; 1440 } // getLeftType 1441 1442 /** Sets the right type*/ 1443 public void setRightType(int aRightType) { 1444 rightType = aRightType; 1445 } // setRightType 1446 1447 /** Get the right type*/ 1448 public int getRightType() { 1449 return rightType; 1450 } // getRightType 1451 1452 /** Get Key document */ 1453 public Document getKeyDocument() { 1454 return keyDocument; 1455 } // getKeyDocument 1456 1457 /** Set Key document */ 1458 public void setKeyDocument(Document aDoc) { 1459 keyDocument = aDoc; 1460 } // setKeyDocument 1461 1462 /** Get Response document */ 1463 public Document getResponseDocument() { 1464 return respDocument; 1465 } // getResponseDocument 1466 1467 /** Set Response document */ 1468 public void setResponseDocument(Document aDoc) { 1469 respDocument = aDoc; 1470 } // setResponseDocument 1471 } // classs DiffSetElement 1472} // class CorpusAnnotationDiff 1473
|
CorpusAnnotationDiff |
|