All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.stanford.nlp.trees.tregex.gui.ScrollableTreeJPanel Maven / Gradle / Ivy

Go to download

Stanford CoreNLP provides a set of natural language analysis tools which can take raw English language text input and give the base forms of words, their parts of speech, whether they are names of companies, people, etc., normalize dates, times, and numeric quantities, mark up the structure of sentences in terms of phrases and word dependencies, and indicate which noun phrases refer to the same entities. It provides the foundational building blocks for higher level text understanding applications.

There is a newer version: 4.5.7
Show newest version
package edu.stanford.nlp.trees.tregex.gui; 
import edu.stanford.nlp.util.logging.Redwood;

import java.awt.*;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.*;
import java.util.List;

import javax.swing.SwingConstants;

import edu.stanford.nlp.ling.CoreLabel;
import edu.stanford.nlp.ling.HasWord;
import edu.stanford.nlp.ling.CoreAnnotations;
import edu.stanford.nlp.parser.ui.TreeJPanel;
import edu.stanford.nlp.trees.Constituent;
import edu.stanford.nlp.trees.Tree;
import edu.stanford.nlp.util.Generics;
import edu.stanford.nlp.util.IntPair;

/**
 * Component for displaying a tree in a JPanel that works correctly with
 * scrolling.
 *
 * @author Anna Rafferty
 */
@SuppressWarnings("serial")
public class ScrollableTreeJPanel extends TreeJPanel    {

  /** A logger for this class */
  private static Redwood.RedwoodChannels log = Redwood.channels(ScrollableTreeJPanel.class);

  private int fontSize = 12;
  private Color defaultColor = Color.BLACK;
  private Color matchedColor = Color.RED;
  private Color tdiffColor = Color.BLUE;
  private String fontName = "";
  private int style = Font.PLAIN;
  private Dimension preferredSize = null;

  private List matchedParts = new ArrayList<>();
  private List matchedPartCoordinates = new ArrayList<>();

  public ScrollableTreeJPanel() {
    super();
  }

  public ScrollableTreeJPanel(int i, int j) {
   super(i,j);
  }

  @Override
  public void paintComponent(Graphics g) {
    superPaint(g);
    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    Font font;
    if ("".equals(fontName)) {
      font = g2.getFont();
      fontName = font.getName();
      style = font.getStyle();
    }

    if(tree != null)
      yieldOffsets = new float[tree.yield().size()];

    font = new Font(fontName, style, this.fontSize);
    g2.setFont(font);
    FontMetrics fM = g2.getFontMetrics();
    Dimension space = getSize();
    double width = width(tree, fM);
    double height = height(tree, fM);
    yieldHeight = height;
    double startX = 0.0;
    double startY = 0.0;
    if (HORIZONTAL_ALIGN == SwingConstants.CENTER) {
      startX = (space.getWidth() - width) / 2.0;
    }
    if (HORIZONTAL_ALIGN == SwingConstants.RIGHT) {
      startX = space.getWidth() - width;
    }
    if (VERTICAL_ALIGN == SwingConstants.CENTER) {
      startY = (space.getHeight() - height) / 2.0;
    }
    if (VERTICAL_ALIGN == SwingConstants.BOTTOM) {
      startY = space.getHeight() - height;
    }
    leafCtr = 0;
    if (matchedParts != null && matchedParts.contains(tree)) {
      paintTree(tree, new Point2D.Double(startX, startY), g2, fM, matchedColor);
    } else {
      paintTree(tree, new Point2D.Double(startX, startY), g2, fM, defaultColor);
      renderRows(g2,fM, defaultColor);
    }
  }

  private void renderRows(Graphics2D g2, FontMetrics fM, Color defaultColor2) {
    double nodeHeight = fM.getHeight();
    double layerMultiplier = (1.0 + belowLineSkip + aboveLineSkip + parentSkip);
    double layerHeight = nodeHeight * layerMultiplier;

    //Draw the yield
    List sentence = tree.yieldHasWord();
    for(int i = 0; i < sentence.size(); i++) {
      g2.drawString(sentence.get(i).word(), yieldOffsets[i], (float) (yieldHeight + layerHeight));
    }

    //Greedily draw the constituents
    final float rowOrigin = (float) (yieldHeight + 2.0*layerHeight);
    List> rows = new ArrayList<>();
    for(Constituent c : diffConstituents) {
      for(int rowIdx = 0; rowIdx < diffConstituents.size(); rowIdx++) {
        float rowHeight = rowOrigin + (float) (rowIdx*layerHeight);
        int ext = (c.end() == (yieldOffsets.length - 1)) ? 0 : 1;
        if(rowIdx >= rows.size()) {
          rows.add(new ArrayList<>());
          rows.get(rowIdx).add(new IntPair(c.start(),c.end()));
          double nodeWidth = fM.stringWidth(c.value());
          g2.drawString(c.value(), yieldOffsets[c.start()], rowHeight);
          try {
            g2.drawLine((int) (yieldOffsets[c.start()] + nodeWidth) + 10, (int) rowHeight, (int) (yieldOffsets[c.end() + ext]) - 15, (int) rowHeight);
          } catch (ArrayIndexOutOfBoundsException e) {
            // This happens if yield of two compared trees do not match.  Just ignore it for now
            // System.err.printf("yieldOffsets.length is %d, c.start() is %d, c.end() is %d, ext is %d%n", yieldOffsets.length, c.start(), c.end(), ext);
          }
          break;

        } else {
          boolean foundOverlap = false;
          for(IntPair span : rows.get(rowIdx)) {
            if(doesOverlap(c,span)) {
              foundOverlap = true;
              break;
            }
          }
          if(!foundOverlap) {
            rows.get(rowIdx).add(new IntPair(c.start(),c.end()));
            double nodeWidth = fM.stringWidth(c.value());
            g2.drawString(c.value(), yieldOffsets[c.start()], rowHeight);
            g2.drawLine((int) (yieldOffsets[c.start()] + nodeWidth) + 10, (int) rowHeight, (int) (yieldOffsets[c.end() + ext]) - 15, (int) rowHeight);
            break;
          }
        }
      }
    }
  }

  private static boolean doesOverlap(Constituent c, IntPair p) {
    if (p.getSource() <= c.start() && p.getTarget() >= c.start())
      return true;
    else if (p.getSource() >= c.start() && p.getTarget() <= c.end())
      return true;
    else if (p.getSource() <= c.end() && p.getTarget() >= c.end())
      return true;
    return false;
  }

  //Tdiff data structures
  private int leafCtr = 0;
  private double yieldHeight;
  private float[] yieldOffsets;


  protected double paintTree(Tree t, Point2D start, Graphics2D g2, FontMetrics fM, Color paintColor) {
    if (t == null) {
      return 0.0;
    }
    String nodeStr = nodeToString(t);
    double nodeWidth = fM.stringWidth(nodeStr);
    double nodeHeight = fM.getHeight();
    double nodeAscent = fM.getAscent();
    WidthResult wr = widthResult(t, fM);
    double treeWidth = wr.width;
    double nodeTab = wr.nodeTab;
    double childTab = wr.childTab;
    double nodeCenter = wr.nodeCenter;
    //double treeHeight = height(t, fM);
    // draw root
    Color curColor = g2.getColor();
    g2.setColor(paintColor);
    g2.drawString(nodeStr, (float) (nodeTab + start.getX()), (float) (start.getY() + nodeAscent));
    g2.setColor(curColor);
    double layerMultiplier = (1.0 + belowLineSkip + aboveLineSkip + parentSkip);
    double layerHeight = nodeHeight * layerMultiplier;
    if (t.isLeaf()) {
      yieldOffsets[leafCtr++] = (float) (nodeTab + start.getX());
      return nodeWidth;
    }
    double childStartX = start.getX() + childTab;
    double childStartY = start.getY() + layerHeight;
    double lineStartX = start.getX() + nodeCenter;
    double lineStartY = start.getY() + nodeHeight * (1.0 + belowLineSkip);
    double lineEndY = lineStartY + nodeHeight * parentSkip;
    // recursively draw children
    for (int i = 0; i < t.children().length; i++) {
      Tree child = t.children()[i];
      double cWidth;
      if(matchedParts != null && matchedParts.contains(child)) {
        // Track where we've painted this matched child
        Point2D.Double coord = new Point2D.Double(childStartX, childStartY);
        matchedPartCoordinates.add(coord);
        cWidth = paintTree(child, coord, g2, fM, matchedColor);
      } else {
        Color col = defaultColor;
        if(((CoreLabel) child.label()).containsKey(CoreAnnotations.DoAnnotation.class))
          col = (((CoreLabel) child.label()).get(CoreAnnotations.DoAnnotation.class)) ? tdiffColor : defaultColor;
        cWidth = paintTree(child, new Point2D.Double(childStartX, childStartY), g2, fM, col);
      }
      // draw connectors
      wr = widthResult(child, fM);
      double lineEndX = childStartX + wr.nodeCenter;
      g2.draw(new Line2D.Double(lineStartX, lineStartY, lineEndX, lineEndY));
      childStartX += cWidth;
      if (i < t.children().length - 1) {
        childStartX += sisterSkip * fM.stringWidth(" ");
      }
    }
    return treeWidth;
  }

  @Override
  public Dimension getPreferredSize() {
    if (preferredSize != null) {
      return preferredSize;
    }
    if (tree == null) {
      return super.getSize();
    }

    FontMetrics fM = getFontMetrics(new Font(fontName, style, fontSize));

    double nodeHeight = fM.getHeight();
    double layerMultiplier = (1.0 + belowLineSkip + aboveLineSkip + parentSkip);
    double layerHeight = nodeHeight * layerMultiplier;
    double layerBuffer = (diffConstituents.size() + 1)*layerHeight;
    layerBuffer += 20.0;

    preferredSize = new Dimension((int)width(tree,fM), (int)(height(tree,fM) + layerBuffer));
    return preferredSize;
  }

  public List getMatchedParts() {
    return matchedParts;
  }

  public void setMatchedParts(List matchedParts) {
    this.matchedParts = matchedParts;
  }

  public List getMatchedPartCoordinates() {
    return matchedPartCoordinates;
  }

  public int getFontSize() {
    return fontSize;
  }

  public void setFontSize(int fontSize) {
    this.fontSize = fontSize;
    preferredSize = null; // stored info invalidated by font change
  }

  public Color getDefaultColor() {
    return defaultColor;
  }

  public void setDefaultColor(Color defaultColor) {
    this.defaultColor = defaultColor;
  }

  public Color getMatchedColor() {
    return matchedColor;
  }

  public void setMatchedColor(Color matchedColor) {
    this.matchedColor = matchedColor;
  }

  public String getFontName() {
    return fontName;
  }

  public void setFontName(String fontName) {
    this.fontName = fontName;
  }


  private Set diffConstituents = Generics.newHashSet();
  public void setDiffConstituents(Set diffConstituents) {
    this.diffConstituents = diffConstituents;
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy