Search in sources :

Example 1 with GridEvent

use of annis.gui.widgets.grid.GridEvent in project ANNIS by korpling.

the class EventExtractor method splitRowsOnIslands.

/**
 * Splits events of a row if they overlap an island.  Islands are areas between
 * the token which are included in the result.
 *
 * @param row
 * @param graph
 * @param text
 * @param startTokenIndex token index of the first token in the match
 * @param endTokenIndex token index of the last token in the match
 */
private static void splitRowsOnIslands(Row row, final SDocumentGraph graph, STextualDS text, long startTokenIndex, long endTokenIndex) {
    BitSet tokenCoverage = new BitSet();
    // get the sorted token
    List<SToken> sortedTokenList = graph.getSortedTokenByText();
    // add all token belonging to the right text to the bit set
    ListIterator<SToken> itToken = sortedTokenList.listIterator();
    while (itToken.hasNext()) {
        SToken t = itToken.next();
        if (text == null || text == CommonHelper.getTextualDSForNode(t, graph)) {
            RelannisNodeFeature feat = (RelannisNodeFeature) t.getFeature(ANNIS_NS, FEAT_RELANNIS_NODE).getValue();
            long tokenIndexRaw = feat.getTokenIndex();
            tokenIndexRaw = clip(tokenIndexRaw, startTokenIndex, endTokenIndex);
            int tokenIndex = (int) (tokenIndexRaw - startTokenIndex);
            tokenCoverage.set(tokenIndex);
        }
    }
    ListIterator<GridEvent> itEvents = row.getEvents().listIterator();
    while (itEvents.hasNext()) {
        GridEvent event = itEvents.next();
        BitSet eventBitSet = new BitSet();
        eventBitSet.set(event.getLeft(), event.getRight() + 1);
        // restrict event bitset on the locations where token are present
        eventBitSet.and(tokenCoverage);
        // and we need to split it
        if (eventBitSet.nextClearBit(event.getLeft()) <= event.getRight()) {
            // remove the original event
            row.removeEvent(itEvents);
            // The event bitset now marks all the locations which the event should
            // cover.
            // Make a list of new events for each connected range in the bitset
            int subElement = 0;
            int offset = eventBitSet.nextSetBit(0);
            while (offset >= 0) {
                int end = eventBitSet.nextClearBit(offset) - 1;
                if (offset < end) {
                    GridEvent newEvent = new GridEvent(event);
                    newEvent.setId(event.getId() + "_islandsplit_" + subElement++);
                    newEvent.setLeft(offset);
                    newEvent.setRight(end);
                    row.addEvent(itEvents, newEvent);
                }
                offset = eventBitSet.nextSetBit(end + 1);
            }
        }
    // end if we need to split
    }
}
Also used : SToken(org.corpus_tools.salt.common.SToken) RelannisNodeFeature(annis.model.RelannisNodeFeature) GridEvent(annis.gui.widgets.grid.GridEvent) BitSet(java.util.BitSet)

Example 2 with GridEvent

use of annis.gui.widgets.grid.GridEvent in project ANNIS by korpling.

the class EventExtractor method removeEmptySpace.

public static void removeEmptySpace(LinkedHashMap<String, ArrayList<Row>> rowsByAnnotation, Row tokenRow) {
    List<Range<Integer>> gaps = new LinkedList<>();
    BitSet totalOccupancyGrid = new BitSet();
    for (Map.Entry<String, ArrayList<Row>> layer : rowsByAnnotation.entrySet()) {
        for (Row r : layer.getValue()) {
            totalOccupancyGrid.or(r.getOccupancyGridCopy());
        }
    }
    // bug report.
    if (tokenRow != null) {
        totalOccupancyGrid.or(tokenRow.getOccupancyGridCopy());
    }
    // The Range class can give us the next bit that is not set. Use this
    // to detect gaps. A gap starts from the next non-set bit and goes to
    // the next set bit.
    Range<Integer> gap = Range.closed(-1, totalOccupancyGrid.nextSetBit(0));
    while (true) {
        int gapStart = totalOccupancyGrid.nextClearBit(gap.upperEndpoint() + 1);
        int gapEnd = totalOccupancyGrid.nextSetBit(gapStart);
        if (gapEnd <= 0) {
            break;
        }
        gap = Range.closed(gapStart, gapEnd - 1);
        gaps.add(gap);
    }
    int gapID = 0;
    int totalOffset = 0;
    for (Range<Integer> gRaw : gaps) {
        // adjust the space range itself
        Range<Integer> g = Range.closed(gRaw.lowerEndpoint() - totalOffset, gRaw.upperEndpoint() - totalOffset);
        int offset = g.upperEndpoint() - g.lowerEndpoint();
        totalOffset += offset;
        for (Entry<String, ArrayList<Row>> rowEntry : rowsByAnnotation.entrySet()) {
            ArrayList<Row> rows = rowEntry.getValue();
            for (Row r : rows) {
                List<GridEvent> eventsCopy = new LinkedList<>(r.getEvents());
                for (GridEvent e : eventsCopy) {
                    if (e.getLeft() >= g.upperEndpoint()) {
                        r.removeEvent(e);
                        e.setLeft(e.getLeft() - offset);
                        e.setRight(e.getRight() - offset);
                        r.addEvent(e);
                    }
                }
                // add a special space event
                String spaceCaption = "";
                if ("tok".equalsIgnoreCase(rowEntry.getKey())) {
                    spaceCaption = "(...)";
                }
                GridEvent spaceEvent = new GridEvent("gap-" + gapID, g.lowerEndpoint(), g.lowerEndpoint(), spaceCaption);
                spaceEvent.setSpace(true);
                r.addEvent(spaceEvent);
                gapID++;
            }
        }
    }
}
Also used : GridEvent(annis.gui.widgets.grid.GridEvent) BitSet(java.util.BitSet) ArrayList(java.util.ArrayList) Range(com.google.common.collect.Range) LinkedList(java.util.LinkedList) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Row(annis.gui.widgets.grid.Row) Map(java.util.Map) LinkedHashMap(java.util.LinkedHashMap)

Example 3 with GridEvent

use of annis.gui.widgets.grid.GridEvent in project ANNIS by korpling.

the class EventExtractor method addAnnotationsForNode.

private static void addAnnotationsForNode(SNode node, SDocumentGraph graph, long startTokenIndex, long endTokenIndex, PDFController pdfController, PDFPageHelper pageNumberHelper, AtomicInteger eventCounter, LinkedHashMap<String, ArrayList<Row>> rowsByAnnotation, boolean addMatch, Set<String> mediaLayer, boolean replaceValueWithMediaIcon) {
    List<String> matchedAnnos = new ArrayList<>();
    SFeature featMatchedAnnos = graph.getFeature(ANNIS_NS, FEAT_MATCHEDANNOS);
    if (featMatchedAnnos != null) {
        matchedAnnos = Splitter.on(',').trimResults().splitToList(featMatchedAnnos.getValue_STEXT());
    }
    // check if the span is a matched node
    SFeature featMatched = node.getFeature(ANNIS_NS, FEAT_MATCHEDNODE);
    Long matchRaw = featMatched == null ? null : featMatched.getValue_SNUMERIC();
    String matchedQualifiedAnnoName = "";
    if (matchRaw != null && matchRaw <= matchedAnnos.size()) {
        matchedQualifiedAnnoName = matchedAnnos.get((int) ((long) matchRaw) - 1);
    }
    // calculate the left and right values of a span
    // TODO: howto get these numbers with Salt?
    RelannisNodeFeature feat = (RelannisNodeFeature) node.getFeature(ANNIS_NS, FEAT_RELANNIS_NODE).getValue();
    long leftLong = feat.getLeftToken();
    long rightLong = feat.getRightToken();
    leftLong = clip(leftLong, startTokenIndex, endTokenIndex);
    rightLong = clip(rightLong, startTokenIndex, endTokenIndex);
    int left = (int) (leftLong - startTokenIndex);
    int right = (int) (rightLong - startTokenIndex);
    for (SAnnotation anno : node.getAnnotations()) {
        ArrayList<Row> rows = rowsByAnnotation.get(anno.getQName());
        if (rows == null) {
            // try again with only the name
            rows = rowsByAnnotation.get(anno.getName());
        }
        if (rows != null) {
            // only do something if the annotation was defined before
            // 1. give each annotation of each span an own row
            Row r = new Row();
            String id = "event_" + eventCounter.incrementAndGet();
            GridEvent event = new GridEvent(id, left, right, anno.getValue_STEXT());
            event.setTooltip(Helper.getQualifiedName(anno));
            if (addMatch && matchRaw != null) {
                long match = matchRaw;
                if (matchedQualifiedAnnoName.isEmpty()) {
                    // always set the match when there is no matched annotation at all
                    event.setMatch(match);
                } else // check if the annotation also matches
                if (matchedQualifiedAnnoName.equals(anno.getQName())) {
                    event.setMatch(match);
                }
            }
            if (node instanceof SSpan) {
                // calculate overlapped SToken
                List<? extends SRelation<? extends SNode, ? extends SNode>> outEdges = graph.getOutRelations(node.getId());
                if (outEdges != null) {
                    for (SRelation<? extends SNode, ? extends SNode> e : outEdges) {
                        if (e instanceof SSpanningRelation) {
                            SSpanningRelation spanRel = (SSpanningRelation) e;
                            SToken tok = spanRel.getTarget();
                            event.getCoveredIDs().add(tok.getId());
                            // get the STextualDS of this token and add it to the event
                            String textID = getTextID(tok, graph);
                            if (textID != null) {
                                event.setTextID(textID);
                            }
                        }
                    }
                }
            // end if span has out edges
            } else if (node instanceof SToken) {
                event.getCoveredIDs().add(node.getId());
                // get the STextualDS of this token and add it to the event
                String textID = getTextID((SToken) node, graph);
                if (textID != null) {
                    event.setTextID(textID);
                }
            }
            // try to get time annotations
            if (mediaLayer == null || mediaLayer.contains(anno.getQName())) {
                double[] startEndTime = TimeHelper.getOverlappedTime(node);
                if (startEndTime.length == 1) {
                    if (replaceValueWithMediaIcon) {
                        event.setValue(" ");
                        event.setTooltip("play excerpt " + event.getStartTime());
                    }
                    event.setStartTime(startEndTime[0]);
                } else if (startEndTime.length == 2) {
                    event.setStartTime(startEndTime[0]);
                    event.setEndTime(startEndTime[1]);
                    if (replaceValueWithMediaIcon) {
                        event.setValue(" ");
                        event.setTooltip("play excerpt " + event.getStartTime() + "-" + event.getEndTime());
                    }
                }
            }
            r.addEvent(event);
            rows.add(r);
            if (pdfController != null && pdfController.sizeOfRegisterdPDFViewer() > 0) {
                String page = pageNumberHelper.getPageFromAnnotation(node);
                if (page != null) {
                    event.setPage(page);
                }
            }
        }
    }
// end for each annotation of span
}
Also used : RelannisNodeFeature(annis.model.RelannisNodeFeature) GridEvent(annis.gui.widgets.grid.GridEvent) SSpan(org.corpus_tools.salt.common.SSpan) SAnnotation(org.corpus_tools.salt.core.SAnnotation) ArrayList(java.util.ArrayList) SToken(org.corpus_tools.salt.common.SToken) SSpanningRelation(org.corpus_tools.salt.common.SSpanningRelation) Row(annis.gui.widgets.grid.Row) SFeature(org.corpus_tools.salt.core.SFeature)

Example 4 with GridEvent

use of annis.gui.widgets.grid.GridEvent in project ANNIS by korpling.

the class EventExtractor method splitRowsOnGaps.

/**
 * Splits events of a row if they contain a gap. Gaps are found using the
 * token index (provided as ANNIS specific {@link SFeature}. Inserted events
 * have a special style to mark them as gaps.
 *
 * @param row
 * @param graph
 * @param startTokenIndex token index of the first token in the match
 * @param endTokenIndex token index of the last token in the match
 */
private static void splitRowsOnGaps(Row row, final SDocumentGraph graph, long startTokenIndex, long endTokenIndex) {
    ListIterator<GridEvent> itEvents = row.getEvents().listIterator();
    while (itEvents.hasNext()) {
        GridEvent event = itEvents.next();
        int lastTokenIndex = -1;
        // sort the coveredIDs
        LinkedList<String> sortedCoveredToken = new LinkedList<>(event.getCoveredIDs());
        Collections.sort(sortedCoveredToken, new Comparator<String>() {

            @Override
            public int compare(String o1, String o2) {
                SNode node1 = graph.getNode(o1);
                SNode node2 = graph.getNode(o2);
                if (node1 == node2) {
                    return 0;
                }
                if (node1 == null) {
                    return -1;
                }
                if (node2 == null) {
                    return +1;
                }
                RelannisNodeFeature feat1 = (RelannisNodeFeature) node1.getFeature(ANNIS_NS, FEAT_RELANNIS_NODE).getValue();
                RelannisNodeFeature feat2 = (RelannisNodeFeature) node2.getFeature(ANNIS_NS, FEAT_RELANNIS_NODE).getValue();
                long tokenIndex1 = feat1.getTokenIndex();
                long tokenIndex2 = feat2.getTokenIndex();
                return ((Long) (tokenIndex1)).compareTo(tokenIndex2);
            }
        });
        // first calculate all gaps
        List<GridEvent> gaps = new LinkedList<>();
        for (String id : sortedCoveredToken) {
            SNode node = graph.getNode(id);
            RelannisNodeFeature feat = (RelannisNodeFeature) node.getFeature(ANNIS_NS, FEAT_RELANNIS_NODE).getValue();
            long tokenIndexRaw = feat.getTokenIndex();
            tokenIndexRaw = clip(tokenIndexRaw, startTokenIndex, endTokenIndex);
            int tokenIndex = (int) (tokenIndexRaw - startTokenIndex);
            // sanity check
            if (tokenIndex >= event.getLeft() && tokenIndex <= event.getRight()) {
                int diff = tokenIndex - lastTokenIndex;
                if (lastTokenIndex >= 0 && diff > 1) {
                    // we detected a gap
                    GridEvent gap = new GridEvent(event.getId() + "_gap_" + gaps.size(), lastTokenIndex + 1, tokenIndex - 1, "");
                    gap.setGap(true);
                    gaps.add(gap);
                }
                lastTokenIndex = tokenIndex;
            } else {
                // reset gap search when discovered there were token we use for
                // hightlighting but do not actually cover
                lastTokenIndex = -1;
            }
        }
        // end for each covered token id
        ListIterator<GridEvent> itGaps = gaps.listIterator();
        // remember the old right value
        int oldRight = event.getRight();
        int gapNr = 0;
        while (itGaps.hasNext()) {
            GridEvent gap = itGaps.next();
            if (gapNr == 0) {
                // shorten original event
                event.setRight(gap.getLeft() - 1);
            }
            // insert the real gap
            itEvents.add(gap);
            int rightBorder = oldRight;
            if (itGaps.hasNext()) {
                // don't use the old event right border since the gap should only go until
                // the next event
                GridEvent nextGap = itGaps.next();
                itGaps.previous();
                rightBorder = nextGap.getLeft() - 1;
            }
            // insert a new event node that covers the rest of the event
            GridEvent after = new GridEvent(event);
            after.setId(event.getId() + "_after_" + gapNr);
            after.setLeft(gap.getRight() + 1);
            after.setRight(rightBorder);
            itEvents.add(after);
            gapNr++;
        }
    }
}
Also used : RelannisNodeFeature(annis.model.RelannisNodeFeature) GridEvent(annis.gui.widgets.grid.GridEvent) SNode(org.corpus_tools.salt.core.SNode) LinkedList(java.util.LinkedList)

Example 5 with GridEvent

use of annis.gui.widgets.grid.GridEvent in project ANNIS by korpling.

the class GridComponent method computeTokenRow.

private Row computeTokenRow(List<SNode> tokens, SDocumentGraph graph, LinkedHashMap<String, ArrayList<Row>> rowsByAnnotation, long startIndex, AtomicInteger tokenOffsetForText) {
    /* we will only add tokens of one texts which is mentioned by any
      included annotation. */
    Set<String> validTextIDs = new HashSet<>();
    if (enforcedText == null) {
        Iterator<ArrayList<Row>> itAllRows = rowsByAnnotation.values().iterator();
        while (itAllRows.hasNext()) {
            ArrayList<Row> rowsForAnnotation = itAllRows.next();
            for (Row r : rowsForAnnotation) {
                validTextIDs.addAll(r.getTextIDs());
            }
        }
        /**
         * we want to show all token if no valid text was found and we have only one
         * text and the first one if there are more than one text.
         */
        List<STextualDS> allTexts = graph.getTextualDSs();
        if (validTextIDs.isEmpty() && allTexts != null && (allTexts.size() == 1 || allTexts.size() == 2)) {
            validTextIDs.add(allTexts.get(0).getId());
        }
    } else {
        validTextIDs.add(enforcedText.getId());
    }
    Row tokenRow = new Row();
    for (SNode t : tokens) {
        // get the Salt ID of the STextualDS of this token
        STextualDS tokenText = CommonHelper.getTextualDSForNode(t, graph);
        // only add token if text ID matches the valid one
        if (tokenText != null && validTextIDs.contains(tokenText.getId())) {
            RelannisNodeFeature feat = (RelannisNodeFeature) t.getFeature(AnnisConstants.ANNIS_NS, AnnisConstants.FEAT_RELANNIS_NODE).getValue();
            long idxLeft = feat.getLeftToken() - startIndex;
            long idxRight = feat.getRightToken() - startIndex;
            if (tokenOffsetForText.get() < 0) {
                // set the token offset by assuming the first idx must be zero
                tokenOffsetForText.set(Math.abs((int) idxLeft));
            }
            String text = extractTextForToken(t, segmentationName);
            GridEvent event = new GridEvent(t.getId(), (int) idxLeft, (int) idxRight, text);
            event.setTextID(tokenText.getId());
            // check if the token is a matched node
            Long match = isCoveredTokenMarked() ? markCoveredTokens(input.getMarkedAndCovered(), t) : tokenMatch(t);
            event.setMatch(match);
            tokenRow.addEvent(event);
        }
    }
    return tokenRow;
}
Also used : RelannisNodeFeature(annis.model.RelannisNodeFeature) SNode(org.corpus_tools.salt.core.SNode) GridEvent(annis.gui.widgets.grid.GridEvent) ArrayList(java.util.ArrayList) STextualDS(org.corpus_tools.salt.common.STextualDS) Row(annis.gui.widgets.grid.Row) HashSet(java.util.HashSet)

Aggregations

GridEvent (annis.gui.widgets.grid.GridEvent)6 RelannisNodeFeature (annis.model.RelannisNodeFeature)5 Row (annis.gui.widgets.grid.Row)4 ArrayList (java.util.ArrayList)4 LinkedList (java.util.LinkedList)3 SNode (org.corpus_tools.salt.core.SNode)3 BitSet (java.util.BitSet)2 HashSet (java.util.HashSet)2 LinkedHashMap (java.util.LinkedHashMap)2 Map (java.util.Map)2 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)2 SToken (org.corpus_tools.salt.common.SToken)2 AnnotationGrid (annis.gui.widgets.grid.AnnotationGrid)1 Range (com.google.common.collect.Range)1 Iterator (java.util.Iterator)1 Set (java.util.Set)1 SDocumentGraph (org.corpus_tools.salt.common.SDocumentGraph)1 SSpan (org.corpus_tools.salt.common.SSpan)1 SSpanningRelation (org.corpus_tools.salt.common.SSpanningRelation)1 STextualDS (org.corpus_tools.salt.common.STextualDS)1