Search in sources :

Example 1 with Row

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

the class EventExtractor method mergeAllRowsIfPossible.

/**
 * Merges the rows. This function uses a heuristical approach that guarantiess
 * to merge all rows into one if there is no conflict at all. If there are
 * conflicts the heuristic will be best-efford but with linear runtime (given
 * a a number of rows).
 *
 * @param rows Will be altered, if no conflicts occcured this wil have only
 * one element.
 */
private static void mergeAllRowsIfPossible(ArrayList<Row> rows) {
    // use fixed seed in order to get consistent results (with random properties)
    Random rand = new Random(5711l);
    int tries = 0;
    // this should be enough to be quite sure we don't miss any optimalization
    // possibility
    final int maxTries = rows.size() * 2;
    // or we give up until too much tries
    while (rows.size() > 1 && tries < maxTries) {
        // choose two random entries
        int oneIdx = rand.nextInt(rows.size());
        int secondIdx = rand.nextInt(rows.size());
        if (oneIdx == secondIdx) {
            // try again if we choose the same rows by accident
            continue;
        }
        Row one = rows.get(oneIdx);
        Row second = rows.get(secondIdx);
        if (one.merge(second)) {
            // remove the second one since it is merged into the first
            rows.remove(secondIdx);
            // success: reset counter
            tries = 0;
        } else {
            // increase counter to avoid endless loops if no improvement is possible
            tries++;
        }
    }
}
Also used : Random(java.util.Random) Row(annis.gui.widgets.grid.Row)

Example 2 with Row

use of annis.gui.widgets.grid.Row 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 Row

use of annis.gui.widgets.grid.Row 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 Row

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

the class EventExtractor method parseSalt.

/**
 * Converts Salt document graph to rows.
 *
 * @param input
 * @param showSpanAnnos
 * @param showTokenAnnos
 * @param mediaLayer  A set of all annotation layers which should be treated as special media layer.
 * @param annotationNames
 * @param replaceValueWithMediaIcon If true the actual value is removed and an icon for playing the media file is shown instead.
 * @param startTokenIndex token index of the first token in the match
 * @param endTokenIndex token index of the last token in the match
 * @param pdfController makes status of all pdfviewer available for the
 * events.
 * @param text If non-null only include annotations for nodes of the specified text.
 * @return
 */
public static LinkedHashMap<String, ArrayList<Row>> parseSalt(VisualizerInput input, boolean showSpanAnnos, boolean showTokenAnnos, List<String> annotationNames, Set<String> mediaLayer, boolean replaceValueWithMediaIcon, long startTokenIndex, long endTokenIndex, PDFController pdfController, STextualDS text) {
    SDocumentGraph graph = input.getDocument().getDocumentGraph();
    // only look at annotations which were defined by the user
    LinkedHashMap<String, ArrayList<Row>> rowsByAnnotation = new LinkedHashMap<>();
    for (String anno : annotationNames) {
        rowsByAnnotation.put(anno, new ArrayList<Row>());
    }
    AtomicInteger eventCounter = new AtomicInteger();
    PDFPageHelper pageNumberHelper = new PDFPageHelper(input);
    if (showSpanAnnos) {
        for (SSpan span : graph.getSpans()) {
            if (text == null || text == CommonHelper.getTextualDSForNode(span, graph)) {
                addAnnotationsForNode(span, graph, startTokenIndex, endTokenIndex, pdfController, pageNumberHelper, eventCounter, rowsByAnnotation, true, mediaLayer, replaceValueWithMediaIcon);
            }
        }
    // end for each span
    }
    if (showTokenAnnos) {
        for (SToken tok : graph.getTokens()) {
            if (text == null || text == CommonHelper.getTextualDSForNode(tok, graph)) {
                addAnnotationsForNode(tok, graph, startTokenIndex, endTokenIndex, pdfController, pageNumberHelper, eventCounter, rowsByAnnotation, false, mediaLayer, replaceValueWithMediaIcon);
            }
        }
    }
    // 2. merge rows when possible
    for (Map.Entry<String, ArrayList<Row>> e : rowsByAnnotation.entrySet()) {
        mergeAllRowsIfPossible(e.getValue());
    }
    // 3. sort events on one row by left token index
    for (Map.Entry<String, ArrayList<Row>> e : rowsByAnnotation.entrySet()) {
        for (Row r : e.getValue()) {
            sortEventsByTokenIndex(r);
        }
    }
    // 4. split up events if they cover islands
    for (Map.Entry<String, ArrayList<Row>> e : rowsByAnnotation.entrySet()) {
        for (Row r : e.getValue()) {
            splitRowsOnIslands(r, graph, text, startTokenIndex, endTokenIndex);
        }
    }
    // 5. split up events if they have gaps
    for (Map.Entry<String, ArrayList<Row>> e : rowsByAnnotation.entrySet()) {
        for (Row r : e.getValue()) {
            splitRowsOnGaps(r, graph, startTokenIndex, endTokenIndex);
        }
    }
    return rowsByAnnotation;
}
Also used : SSpan(org.corpus_tools.salt.common.SSpan) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) SToken(org.corpus_tools.salt.common.SToken) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) SDocumentGraph(org.corpus_tools.salt.common.SDocumentGraph) PDFPageHelper(annis.libgui.PDFPageHelper) Row(annis.gui.widgets.grid.Row) Map(java.util.Map) LinkedHashMap(java.util.LinkedHashMap)

Example 5 with Row

use of annis.gui.widgets.grid.Row 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

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