Search in sources :

Example 1 with Row

use of org.corpus_tools.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 optimization
    // 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(org.corpus_tools.annis.gui.widgets.grid.Row)

Example 2 with Row

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

the class SingleGridComponent method createAnnotationGrid.

private boolean createAnnotationGrid() {
    String resultID = input.getId();
    grid = new AnnotationGrid(mediaController, pdfController, resultID);
    grid.addStyleName(getMainStyle());
    grid.addStyleName(Helper.CORPUS_FONT_FORCE);
    grid.setEscapeHTML(Boolean.parseBoolean(input.getMappings().getOrDefault(MAPPING_ESCAPE_HTML, "true")));
    LinkedList<Class<? extends SNode>> types = new LinkedList<>();
    if (isShowingSpanAnnotations()) {
        types.add(SSpan.class);
    }
    if (isShowingTokenAnnotations()) {
        types.add(SToken.class);
    }
    grid.setAnnosWithNamespace(EventExtractor.computeDisplayedNamespace(input, types));
    layout.addComponent(grid);
    SDocumentGraph graph = input.getDocument().getDocumentGraph();
    List<SNode> sortedSegmentationNodes = Helper.getSortedSegmentationNodes(this.segmentationName, graph);
    Map<SToken, Integer> token2index = Helper.createToken2IndexMap(graph, this.enforcedText);
    Preconditions.checkArgument(!token2index.isEmpty(), "Token list must be non-empty");
    LinkedHashMap<String, ArrayList<Row>> rowsByAnnotation = computeAnnotationRows(token2index);
    // Get Mappings
    String gridTemplates = input.getMappings().getOrDefault(MAPPING_GRID_TEMPLATES, "");
    // Parse Mappings
    if (!gridTemplates.equals("")) {
        String[] split = gridTemplates.split("\\|\\|");
        for (String s : split) {
            // example of s: entity="person"==>:), or infstat==><b>%%value%%</b>
            String[] unit_split = s.split("==>");
            Set<Map.Entry<String, ArrayList<Row>>> set = rowsByAnnotation.entrySet();
            // Displaying elements of LinkedHashMap
            Iterator<Map.Entry<String, ArrayList<Row>>> iterator = set.iterator();
            while (iterator.hasNext()) {
                // iterate over rows
                Map.Entry<String, ArrayList<Row>> me = iterator.next();
                String rowKey = me.getKey();
                ArrayList<Row> rowValue = me.getValue();
                for (Row rowValue1 : rowValue) {
                    ArrayList<GridEvent> rowEvents = rowValue1.getEvents();
                    if (unit_split[0].indexOf('=') < 0) {
                        // unit_split[0] is a single instruction, e.g., infstat
                        // check if the key of a row in rowsByAnnotation is unit_split[0]
                        // if it is, we need to change every value of this row, else we dont do anything
                        String rowName = rowKey.split("::")[1];
                        if (rowName.equals(unit_split[0])) {
                            // iterate over all values and replace the value with the unit_split[1]
                            for (GridEvent ev : rowEvents) {
                                String origValue = ev.getValue();
                                String newValue = unit_split[1].replaceAll("%%value%%", origValue);
                                ev.setValue(newValue);
                            }
                        }
                    } else {
                        // its a instruction like entity='person'
                        // first break this split into entity and person
                        // check if rowKey is entity, then when iterating over events, check if value is
                        // person
                        String rowName = rowKey.split("::")[1];
                        String targetRow = unit_split[0].split("=")[0];
                        String targetValue = unit_split[0].split("=")[1].replaceAll("\"", "");
                        if (rowName.equals(targetRow)) {
                            // iterate over all values and replace the value with the unit_split[1]
                            for (GridEvent ev : rowEvents) {
                                String origValue = ev.getValue();
                                if (origValue.equals(targetValue)) {
                                    ev.setValue(unit_split[1]);
                                }
                            // String newValue = unit_split[1].replaceAll("%%value%%",origValue);
                            }
                        }
                    }
                }
            }
        }
    }
    // add tokens as row
    Row tokenRow = computeTokenRow(sortedSegmentationNodes, graph, rowsByAnnotation, token2index);
    String tokenRowCaption = "tok";
    if (isHidingToken()) {
        // We have to add the invisible token row avoid issues with the layout
        // (see https://github.com/korpling/ANNIS/issues/524)
        // but we don't want the invisible token layer to override an actual "tok"
        // annotation layer (see https://github.com/korpling/ANNIS/issues/596)
        tokenRow.setStyle("invisible_token");
        tokenRowCaption = "";
        grid.setTokRowKey("");
    }
    if (isTokenFirst()) {
        // copy original list but add token row at the beginning
        LinkedHashMap<String, ArrayList<Row>> newList = new LinkedHashMap<>();
        newList.put(tokenRowCaption, Lists.newArrayList(tokenRow));
        newList.putAll(rowsByAnnotation);
        rowsByAnnotation = newList;
    } else {
        // just add the token row to the end of the list
        rowsByAnnotation.put(tokenRowCaption, Lists.newArrayList(tokenRow));
    }
    EventExtractor.removeEmptySpace(rowsByAnnotation, tokenRow);
    // check if the token row only contains empty values
    boolean tokenRowIsEmpty = true;
    for (GridEvent tokenEvent : tokenRow.getEvents()) {
        if (tokenEvent.getValue() != null && !tokenEvent.getValue().trim().isEmpty()) {
            tokenRowIsEmpty = false;
            break;
        }
    }
    if (!isHidingToken() && canShowEmptyTokenWarning()) {
        lblEmptyToken.setVisible(tokenRowIsEmpty);
    }
    grid.setRowsByAnnotation(rowsByAnnotation);
    return !tokenRowIsEmpty;
}
Also used : SNode(org.corpus_tools.salt.core.SNode) GridEvent(org.corpus_tools.annis.gui.widgets.grid.GridEvent) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) SToken(org.corpus_tools.salt.common.SToken) AnnotationGrid(org.corpus_tools.annis.gui.widgets.grid.AnnotationGrid) SDocumentGraph(org.corpus_tools.salt.common.SDocumentGraph) LinkedList(java.util.LinkedList) Row(org.corpus_tools.annis.gui.widgets.grid.Row) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map)

Example 3 with Row

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

the class SingleGridComponent method computeTokenRow.

private Row computeTokenRow(List<SNode> tokens, SDocumentGraph graph, LinkedHashMap<String, ArrayList<Row>> rowsByAnnotation, Map<SToken, Integer> token2index) {
    /*
     * 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 is 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 = Helper.getTextualDSForNode(t, graph);
        // only add token if text ID matches the valid one
        if (tokenText != null && validTextIDs.contains(tokenText.getId()) && hasSegmentation(t, this.segmentationName)) {
            Range<Integer> coveredRange = Helper.getLeftRightSpan(t, graph, token2index);
            String text = extractTextForToken(t, segmentationName);
            GridEvent event = new GridEvent(t.getId(), coveredRange.lowerEndpoint(), coveredRange.upperEndpoint(), 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 : SNode(org.corpus_tools.salt.core.SNode) GridEvent(org.corpus_tools.annis.gui.widgets.grid.GridEvent) ArrayList(java.util.ArrayList) STextualDS(org.corpus_tools.salt.common.STextualDS) Row(org.corpus_tools.annis.gui.widgets.grid.Row) HashSet(java.util.HashSet)

Example 4 with Row

use of org.corpus_tools.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 token2index
 * @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, Map<SToken, Integer> token2index, 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 == Helper.getTextualDSForNode(span, graph)) {
                addAnnotationsForNode(span, graph, token2index, pdfController, pageNumberHelper, eventCounter, rowsByAnnotation, true, mediaLayer, replaceValueWithMediaIcon);
            }
        }
    // end for each span
    }
    if (showTokenAnnos) {
        for (SToken tok : graph.getTokens()) {
            if (text == null || text == Helper.getTextualDSForNode(tok, graph)) {
                addAnnotationsForNode(tok, graph, token2index, 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, token2index);
        }
    }
    // 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, token2index);
        }
    }
    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(org.corpus_tools.annis.gui.PDFPageHelper) Row(org.corpus_tools.annis.gui.widgets.grid.Row) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map)

Example 5 with Row

use of org.corpus_tools.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(org.corpus_tools.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(org.corpus_tools.annis.gui.widgets.grid.Row) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map)

Aggregations

Row (org.corpus_tools.annis.gui.widgets.grid.Row)9 ArrayList (java.util.ArrayList)8 GridEvent (org.corpus_tools.annis.gui.widgets.grid.GridEvent)7 GridKt (com.github.mvysny.kaributesting.v8.GridKt)3 LocatorJ._click (com.github.mvysny.kaributesting.v8.LocatorJ._click)3 LocatorJ._find (com.github.mvysny.kaributesting.v8.LocatorJ._find)3 LocatorJ._get (com.github.mvysny.kaributesting.v8.LocatorJ._get)3 LocatorJ._setValue (com.github.mvysny.kaributesting.v8.LocatorJ._setValue)3 MockVaadin (com.github.mvysny.kaributesting.v8.MockVaadin)3 NotificationsKt (com.github.mvysny.kaributesting.v8.NotificationsKt)3 DataProvider (com.vaadin.data.provider.DataProvider)3 ListDataProvider (com.vaadin.data.provider.ListDataProvider)3 VaadinIcons (com.vaadin.icons.VaadinIcons)3 Page (com.vaadin.server.Page)3 ContentMode (com.vaadin.shared.ui.ContentMode)3 UIScopeImpl (com.vaadin.spring.internal.UIScopeImpl)3 Accordion (com.vaadin.ui.Accordion)3 Button (com.vaadin.ui.Button)3 ComboBox (com.vaadin.ui.ComboBox)3 Component (com.vaadin.ui.Component)3