Example usage for java.util TreeMap floorEntry

List of usage examples for java.util TreeMap floorEntry

Introduction

In this page you can find the example usage for java.util TreeMap floorEntry.

Prototype

public Map.Entry<K, V> floorEntry(K key) 

Source Link

Usage

From source file:Main.java

public static void main(String[] args) {

    TreeMap<Integer, String> treemap = new TreeMap<Integer, String>();

    // populating tree map
    treemap.put(2, "two");
    treemap.put(1, "one");
    treemap.put(3, "three");
    treemap.put(6, "six");
    treemap.put(5, "from java2s.com");

    System.out.println("Checking floor entry for 6");
    System.out.println("Value is: " + treemap.floorEntry(6));
}

From source file:eu.crisis_economics.abm.algorithms.statistics.FloorInterpolator.java

@Override
public UnivariateFunction interpolate(final double[] x, final double[] y)
        throws MathIllegalArgumentException, DimensionMismatchException {
    Preconditions.checkNotNull(x, y);/*from   www. j ava 2 s  . c  o m*/
    if (x.length != y.length)
        throw new DimensionMismatchException(x.length, y.length);
    final int seriesLength = x.length;
    if (seriesLength == 0)
        throw new IllegalArgumentException(
                "FloorInterpolator.interpolate: input data is empty. Interpolation cannot continue.");
    final TreeMap<Double, Double> tree = new TreeMap<Double, Double>();
    for (int i = 0; i < seriesLength; ++i)
        tree.put(x[i], y[i]);
    final UnivariateFunction result = new UnivariateFunction() {
        @Override
        public double value(final double t) {
            if (t < x[0])
                return y[0];
            else if (t > x[seriesLength - 1])
                return y[seriesLength - 1];
            else
                return tree.floorEntry(t).getValue();
        }
    };
    return result;
}

From source file:com.vgi.mafscaling.Rescale.java

private void calculateNewGs(ArrayList<Double> newVoltArray, ArrayList<Double> newGsArray) {
    TreeMap<Double, Integer> vgsTree = new TreeMap<Double, Integer>();
    for (int i = origVoltArray.size() - 1; i >= 0; --i)
        vgsTree.put(origVoltArray.get(i), i);
    Map.Entry<Double, Integer> kv;
    double x0, y0, x, y, x1, y1;
    for (int i = 1; i < newVoltArray.size(); ++i) {
        x = newVoltArray.get(i);//  w  w  w. j ava2s  .c  o  m
        kv = vgsTree.floorEntry(x);
        if (kv == null) {
            newGsArray.add(0.0);
            continue;
        }
        x0 = kv.getKey();
        if (x0 == x) {
            newGsArray.add(origGsArray.get(kv.getValue()));
            continue;
        }
        y0 = origGsArray.get(kv.getValue());
        kv = vgsTree.ceilingEntry(x);
        if (kv == null) {
            newGsArray.add(0.0);
            continue;
        }
        x1 = kv.getKey();
        y1 = origGsArray.get(kv.getValue());
        y = Utils.linearInterpolation(x, x0, x1, y0, y1);
        newGsArray.add(y);
    }
}

From source file:com.datatorrent.contrib.hdht.HDHTWriter.java

/**
 * Flush changes from write cache to disk. New data files will be written and meta data replaced atomically. The flush
 * frequency determines availability of changes to external readers.
 *
 * @throws IOException/*from  ww w  . j av  a  2s  .c om*/
 */
private void writeDataFiles(Bucket bucket) throws IOException {
    BucketIOStats ioStats = getOrCretaStats(bucket.bucketKey);
    LOG.debug("Writing data files in bucket {}", bucket.bucketKey);
    // copy meta data on write
    BucketMeta bucketMetaCopy = kryo.copy(getMeta(bucket.bucketKey));

    /** Process purge requests before flushing data from cache to maintain
     * the oder or purge and put operations. This makes sure that purged data
     * removed from file, before new data is added to the files */
    HashSet<String> filesToDelete = Sets.newHashSet();
    bucketMetaCopy = processPurge(bucket, bucketMetaCopy, filesToDelete);

    // bucket keys by file
    TreeMap<Slice, BucketFileMeta> bucketSeqStarts = bucketMetaCopy.files;
    Map<BucketFileMeta, Map<Slice, Slice>> modifiedFiles = Maps.newHashMap();

    for (Map.Entry<Slice, byte[]> entry : bucket.frozenWriteCache.entrySet()) {
        // find file for key
        Map.Entry<Slice, BucketFileMeta> floorEntry = bucketSeqStarts.floorEntry(entry.getKey());
        BucketFileMeta floorFile;
        if (floorEntry != null) {
            floorFile = floorEntry.getValue();
        } else {
            floorEntry = bucketSeqStarts.firstEntry();
            if (floorEntry == null || floorEntry.getValue().name != null) {
                // no existing file or file with higher key
                floorFile = new BucketFileMeta();
            } else {
                // placeholder for new keys, move start key
                floorFile = floorEntry.getValue();
                bucketSeqStarts.remove(floorEntry.getKey());
            }
            floorFile.startKey = entry.getKey();
            if (floorFile.startKey.length != floorFile.startKey.buffer.length) {
                // normalize key for serialization
                floorFile.startKey = new Slice(floorFile.startKey.toByteArray());
            }
            bucketSeqStarts.put(floorFile.startKey, floorFile);
        }

        Map<Slice, Slice> fileUpdates = modifiedFiles.get(floorFile);
        if (fileUpdates == null) {
            modifiedFiles.put(floorFile, fileUpdates = Maps.newHashMap());
        }
        fileUpdates.put(entry.getKey(), new Slice(entry.getValue()));
    }

    // write modified files
    for (Map.Entry<BucketFileMeta, Map<Slice, Slice>> fileEntry : modifiedFiles.entrySet()) {
        BucketFileMeta fileMeta = fileEntry.getKey();
        TreeMap<Slice, Slice> fileData = new TreeMap<Slice, Slice>(getKeyComparator());

        if (fileMeta.name != null) {
            // load existing file
            long start = System.currentTimeMillis();
            FileReader reader = store.getReader(bucket.bucketKey, fileMeta.name);
            reader.readFully(fileData);
            ioStats.dataBytesRead += store.getFileSize(bucket.bucketKey, fileMeta.name);
            ioStats.dataReadTime += System.currentTimeMillis() - start;
            /* these keys are re-written */
            ioStats.dataKeysRewritten += fileData.size();
            ioStats.filesReadInCurrentWriteCycle++;
            ioStats.dataFilesRead++;
            reader.close();
            filesToDelete.add(fileMeta.name);
        }

        // apply updates
        fileData.putAll(fileEntry.getValue());
        // new file
        writeFile(bucket, bucketMetaCopy, fileData);
    }

    LOG.debug("Files written {} files read {}", ioStats.filesWroteInCurrentWriteCycle,
            ioStats.filesReadInCurrentWriteCycle);
    // flush meta data for new files
    try {
        LOG.debug("Writing {} with {} file entries", FNAME_META, bucketMetaCopy.files.size());
        OutputStream os = store.getOutputStream(bucket.bucketKey, FNAME_META + ".new");
        Output output = new Output(os);
        bucketMetaCopy.committedWid = bucket.committedLSN;
        bucketMetaCopy.recoveryStartWalPosition = bucket.recoveryStartWalPosition;
        kryo.writeClassAndObject(output, bucketMetaCopy);
        output.close();
        os.close();
        store.rename(bucket.bucketKey, FNAME_META + ".new", FNAME_META);
    } catch (IOException e) {
        throw new RuntimeException("Failed to write bucket meta data " + bucket.bucketKey, e);
    }

    // clear pending changes
    ioStats.dataKeysWritten += bucket.frozenWriteCache.size();
    // switch to new version
    this.metaCache.put(bucket.bucketKey, bucketMetaCopy);

    // delete old files
    for (String fileName : filesToDelete) {
        store.delete(bucket.bucketKey, fileName);
    }
    invalidateReader(bucket.bucketKey, filesToDelete);
    // clearing cache after invalidating readers
    bucket.frozenWriteCache.clear();

    // cleanup WAL files which are not needed anymore.
    minimumRecoveryWalPosition = bucketMetaCopy.recoveryStartWalPosition;
    for (Long bucketId : this.bucketKeys) {
        BucketMeta meta = getMeta(bucketId);
        if (meta.recoveryStartWalPosition.fileId < minimumRecoveryWalPosition.fileId
                || (meta.recoveryStartWalPosition.fileId == minimumRecoveryWalPosition.fileId
                        && meta.recoveryStartWalPosition.offset < minimumRecoveryWalPosition.offset)) {
            minimumRecoveryWalPosition = meta.recoveryStartWalPosition;
        }
    }
    this.wal.cleanup(minimumRecoveryWalPosition.fileId);
    ioStats.filesReadInCurrentWriteCycle = 0;
    ioStats.filesWroteInCurrentWriteCycle = 0;
}

From source file:edu.cmu.cs.lti.discoursedb.annotation.brat.io.BratService.java

/**
 * Imports a thread in Brat stand-off format into discoursedb.
 * /*from  ww  w  . j  av a  2  s .co  m*/
 * @param inputFolder folder with the brat annotation and meta data
 * @param baseFileName the base filename for the current thread to be imported
 * @return an info object containing lists of ids of annotations and featured to be deleted after the import 
 * @throws IOException if any exception occurs while reading the brat annotations or meta data
 */
@Transactional(value = "coreTransactionManager", propagation = Propagation.REQUIRED, readOnly = false)
private CleanupInfo importThreadFromBrat(String inputFolder, String baseFileName) throws IOException {
    Assert.hasText(inputFolder,
            "inputFolder parameter cannot be empty [importThread(" + inputFolder + ", " + baseFileName + ")]");
    Assert.hasText(baseFileName,
            "baseFileName parameter cannot be empty [importThread(" + inputFolder + ", " + baseFileName + ")]");

    File annFile = new File(inputFolder, baseFileName + ".ann");
    File offsetFile = new File(inputFolder, baseFileName + ".offsets");
    File versionsFile = new File(inputFolder, baseFileName + ".versions");

    // get mapping from entity to offset
    TreeMap<Integer, OffsetInfo> offsetToOffsetInfo = getOffsetToOffsetInfoMap(offsetFile);

    // keep track of versions of orginally exported annotations and features
    Map<String, VersionInfo> annotationBratIdToVersionInfo = getBratIdToDdbIdMap(versionsFile,
            AnnotationSourceType.DDB_ANNOTATION);
    Map<String, VersionInfo> featureBratIdToVersionInfo = getBratIdToDdbIdMap(versionsFile,
            AnnotationSourceType.DDB_FEATURE);

    DiscoursePart dp = dpService
            .findOne(Long.parseLong(baseFileName.substring(baseFileName.lastIndexOf("_") + 1))).get();
    SystemUser sysUser = sysUserService.getSystemUser().get();

    //Init ddb annotation stats for deletion handling
    Set<Long> ddbAnnotationIds = new HashSet<>();
    Set<Long> ddbFeatureIds = new HashSet<>();
    //extract annotations on Contributions
    for (AnnotationInstance anno : annoService.findContributionAnnotationsByDiscoursePart(dp)) {
        ddbAnnotationIds.add(anno.getId());
        anno.setAnnotator(sysUser);
        ;
        if (anno.getFeatures() != null) {
            ddbFeatureIds.addAll(anno.getFeatures().stream().map(f -> f.getId()).collect(Collectors.toList()));
        }
    }
    //extract annotations on Content entities
    for (AnnotationInstance anno : annoService.findCurrentRevisionAnnotationsByDiscoursePart(dp)) {
        ddbAnnotationIds.add(anno.getId());
        anno.setAnnotator(sysUser);
        if (anno.getFeatures() != null) {
            ddbFeatureIds.addAll(anno.getFeatures().stream().map(f -> f.getId()).collect(Collectors.toList()));
        }
    }
    log.info(ddbAnnotationIds.size() + " annotations within current thread available in DiscoursDB.");
    log.info(ddbFeatureIds.size() + " features within current thread available in DiscoursDB.");

    List<String> bratStandoffEncodedStrings = FileUtils.readLines(annFile);
    //sorting in reverse order assures that Attribute annotations (A) are imported after text-bound annotations (T)
    Collections.sort(bratStandoffEncodedStrings, Collections.reverseOrder());
    for (String bratStandoffEncodedString : bratStandoffEncodedStrings) {

        // create BratAnnotation object from Brat-Stand-off-Encoded String
        // offset correction will be done later
        BratAnnotation bratAnno = new BratAnnotation(bratStandoffEncodedString);

        if (bratAnno.getType() == BratAnnotationType.BRAT_TEXT) {

            Entry<Integer, OffsetInfo> offset = offsetToOffsetInfo.floorEntry(bratAnno.getBeginIndex());
            Contribution contrib = contribService.findOne(offset.getValue().getDiscourseDbContributionId())
                    .get();
            Content content = contentService.findOne(offset.getValue().getDiscourseDbContentId()).get();
            long separatorStartIndex = offset.getKey();
            long separatorEndIndex = separatorStartIndex + BratSeparator.length;
            long textEndIndex = separatorEndIndex + content.getText().length();

            // CONTRIBUTION LABEL: Annotation is completely within a separator
            if (bratAnno.getBeginIndex() >= separatorStartIndex && bratAnno.getBeginIndex() <= separatorEndIndex
                    && bratAnno.getEndIndex() >= separatorStartIndex
                    && bratAnno.getEndIndex() <= separatorEndIndex) {

                // check if annotation already existed before
                if (annotationBratIdToVersionInfo.keySet().contains(bratAnno.getId())) {
                    VersionInfo entityInfo = annotationBratIdToVersionInfo.get(bratAnno.getId());

                    ddbAnnotationIds.remove(entityInfo.getDiscourseDBEntityId()); //update deletion stats

                    AnnotationInstance existingAnno = annoService
                            .findOneAnnotationInstance(entityInfo.getDiscourseDBEntityId()).get();

                    //check if the anno version in the database still matches the anno version we initially exported 
                    if (existingAnno.getEntityVersion() == entityInfo.getDiscourseDBEntityVersion()) {
                        existingAnno.setBeginOffset(0);
                        existingAnno.setEndOffset(0);
                        existingAnno.setType(bratAnno.getAnnotationLabel());
                    } else {
                        log.error(
                                "Entity changed in DiscourseDB since the data was last import but also changed in the exported file. Cannot import annotation.");
                    }

                } else {
                    // anno is new and didn't exist in ddb before
                    AnnotationInstance newAnno = annoService
                            .createTypedAnnotation(bratAnno.getAnnotationLabel());
                    annoService.addAnnotation(contrib, newAnno);
                    contribService.save(contrib); //this should happen in addAnnotation. Filed Issue #15
                    //update version file
                    annotationBratIdToVersionInfo.put(bratAnno.getId(),
                            new VersionInfo(AnnotationSourceType.DDB_ANNOTATION, bratAnno.getId(),
                                    newAnno.getId(), newAnno.getEntityVersion()));
                }
            }
            // SPAN ANNOTATION WITHIN CONTRIBUTION TEXT (does neither span over separator nor over multiple contributions)
            else if (bratAnno.getBeginIndex() > separatorEndIndex && bratAnno.getBeginIndex() <= textEndIndex
                    && bratAnno.getEndIndex() > separatorEndIndex && bratAnno.getEndIndex() <= textEndIndex) {

                // calculate offset corrected index values for span annotation
                int offsetCorrectedBeginIdx = bratAnno.getBeginIndex() - offset.getKey() - BratSeparator.length
                        - 1;
                int offsetCorrectedEndIdx = bratAnno.getEndIndex() - offset.getKey() - BratSeparator.length - 1;

                // check if annotation already existed before
                if (annotationBratIdToVersionInfo.keySet().contains(bratAnno.getId())) {
                    VersionInfo entityInfo = annotationBratIdToVersionInfo.get(bratAnno.getId());
                    ddbAnnotationIds.remove(entityInfo.getDiscourseDBEntityId()); //update deletion stats

                    // Anno already existed. Check for changes.
                    AnnotationInstance existingAnno = annoService
                            .findOneAnnotationInstance(entityInfo.getDiscourseDBEntityId()).get();

                    //check if the anno version in the database still matches the anno version we initially exported
                    //if so, we can update
                    if (existingAnno.getEntityVersion() == entityInfo.getDiscourseDBEntityVersion()) {
                        existingAnno.setBeginOffset(offsetCorrectedBeginIdx);
                        existingAnno.setEndOffset(offsetCorrectedEndIdx);
                        existingAnno.setType(bratAnno.getAnnotationLabel());
                    } else {
                        log.error(
                                "Entity changed in DiscourseDB since the data was last import but also changed in the exported file. Cannot import annotation.");
                    }
                } else {
                    // Anno is new and didn't exist in ddb before. Create it.
                    AnnotationInstance newAnno = annoService
                            .createTypedAnnotation(bratAnno.getAnnotationLabel());
                    newAnno.setBeginOffset(offsetCorrectedBeginIdx);
                    newAnno.setEndOffset(offsetCorrectedEndIdx);
                    annoService.addAnnotation(content, newAnno);
                    contentService.save(content); //this should happen in addAnnotation. Filed Issue #15
                    //update version file
                    annotationBratIdToVersionInfo.put(bratAnno.getId(),
                            new VersionInfo(AnnotationSourceType.DDB_ANNOTATION, bratAnno.getId(),
                                    newAnno.getId(), newAnno.getEntityVersion()));
                }
            } else {
                log.error(
                        "Annotation extends over contribution separator(s) AND text. You can only annotate within a separator or within a contribution. Skipping this annotation...");
            }
        } else if (bratAnno.getType() == BratAnnotationType.BRAT_NOTE) {

            VersionInfo entityInfo = featureBratIdToVersionInfo.get(bratAnno.getId());

            // check if feature already existed before
            if (featureBratIdToVersionInfo.keySet().contains(bratAnno.getId())) {
                ddbFeatureIds.remove(entityInfo.getDiscourseDBEntityId()); //update deletion stats

                // feature already existed
                Feature existingFeature = annoService.findOneFeature(entityInfo.getDiscourseDBEntityId()).get();

                //check if the feature version in the database still matches the feature version we initially exported 
                if (existingFeature.getEntityVersion() == entityInfo.getDiscourseDBEntityVersion()) {
                    //check for and apply changes
                    if (existingFeature.getValue().equalsIgnoreCase(bratAnno.getAnnotationLabel())) {
                        existingFeature.setValue(bratAnno.getAnnotationLabel());
                    }
                } else {
                    log.error(
                            "Entity changed in DiscourseDB since the data was last import but also changed in the exported file. Cannot import feature.");
                }
            } else {
                // feature didn't exist in database yet. Create it.
                VersionInfo referenceAnnotationInfo = annotationBratIdToVersionInfo
                        .get(bratAnno.getSourceAnnotationId());
                if (referenceAnnotationInfo != null) {
                    AnnotationInstance referenceAnno = annoService
                            .findOneAnnotationInstance(referenceAnnotationInfo.getDiscourseDBEntityId()).get();
                    Feature newFeature = annoService.createTypedFeature(bratAnno.getNoteText(),
                            bratAnno.getType().name());
                    //update version file
                    featureBratIdToVersionInfo.put(bratAnno.getId(),
                            new VersionInfo(AnnotationSourceType.DDB_FEATURE, bratAnno.getId(),
                                    newFeature.getId(), newFeature.getEntityVersion()));
                    annoService.addFeature(referenceAnno, newFeature);
                    annoService.saveFeature(newFeature); //this should happen in addFeature. Filed Issue #15
                } else {
                    log.error("Cannot find the annotation this feature applies to.");
                }
            }
        } else {
            //Implement import capabilities for other Brat Annotation types here
            log.error("Unsupported Annotation type " + bratAnno.getType() + " Skipping.");
        }
    }

    //Regenerate the version infos updated data from the newly created annotations 
    List<VersionInfo> updatedVersionInfo = new ArrayList<>();
    updatedVersionInfo.addAll(annotationBratIdToVersionInfo.values());
    updatedVersionInfo.addAll(featureBratIdToVersionInfo.values());
    FileUtils.writeLines(versionsFile, updatedVersionInfo);

    //return info about entities to be deleted
    return new CleanupInfo(versionsFile, ddbFeatureIds, ddbAnnotationIds);
}

From source file:nl.rivm.cib.episim.model.disease.infection.MSEIRSPlot.java

@Override
public void start(final Stage stage) {
    final SIRConfig conf = ConfigFactory.create(SIRConfig.class);
    final double[] t = conf.t();
    final long[] pop = conf.population();
    final double n0 = Arrays.stream(pop).sum();
    final String[] colors = conf.colors(), colors2 = conf.colors2();

    final Pane plot = new Pane();
    plot.setPrefSize(400, 300);/*from   w  w w.j  av  a 2s  . co m*/
    plot.setMinSize(50, 50);

    final NumberAxis xAxis = new NumberAxis(t[0], t[1], (t[1] - t[0]) / 10);
    final NumberAxis yAxis = new NumberAxis(0, n0, n0 / 10);
    final Pane axes = new Pane();
    axes.prefHeightProperty().bind(plot.heightProperty());
    axes.prefWidthProperty().bind(plot.widthProperty());

    xAxis.setSide(Side.BOTTOM);
    xAxis.setMinorTickVisible(false);
    xAxis.setPrefWidth(axes.getPrefWidth());
    xAxis.prefWidthProperty().bind(axes.widthProperty());
    xAxis.layoutYProperty().bind(axes.heightProperty());

    yAxis.setSide(Side.LEFT);
    yAxis.setMinorTickVisible(false);
    yAxis.setPrefHeight(axes.getPrefHeight());
    yAxis.prefHeightProperty().bind(axes.heightProperty());
    yAxis.layoutXProperty().bind(Bindings.subtract(1, yAxis.widthProperty()));
    axes.getChildren().setAll(xAxis, yAxis);

    final Label lbl = new Label(String.format("R0=%.1f, recovery=%.1ft\nSIR(0)=%s", conf.reproduction(),
            conf.recovery(), Arrays.toString(pop)));
    lbl.setTextAlignment(TextAlignment.CENTER);
    lbl.setTextFill(Color.WHITE);

    final Path[] deterministic = { new Path(), new Path(), new Path() };
    IntStream.range(0, pop.length).forEach(i -> {
        final Color color = Color.valueOf(colors[i]);
        final Path path = deterministic[i];
        path.setStroke(color.deriveColor(0, 1, 1, 0.6));
        path.setStrokeWidth(2);
        path.setClip(new Rectangle(0, 0, plot.getPrefWidth(), plot.getPrefHeight()));
    });

    plot.getChildren().setAll(axes);

    // fill paths with integration estimates
    final double xl = xAxis.getLowerBound(), sx = plot.getPrefWidth() / (xAxis.getUpperBound() - xl),
            yh = plot.getPrefHeight(), sy = yh / (yAxis.getUpperBound() - yAxis.getLowerBound());
    final TreeMap<Double, Integer> iDeterministic = new TreeMap<>();

    MSEIRSTest.deterministic(conf, () -> new DormandPrince853Integrator(1.0E-8, 10, 1.0E-20, 1.0E-20))
            .subscribe(yt -> {
                iDeterministic.put(yt.getKey(), deterministic[0].getElements().size());
                final double[] y = yt.getValue();
                final double x = (yt.getKey() - xl) * sx;
                for (int i = 0; i < y.length; i++) {
                    final double yi = yh - y[i] * sy;
                    final PathElement di = deterministic[i].getElements().isEmpty() ? new MoveTo(x, yi)
                            : new LineTo(x, yi);
                    deterministic[i].getElements().add(di);
                }
            }, e -> LOG.error("Problem", e), () -> plot.getChildren().addAll(deterministic));

    final Path[] stochasticTau = { new Path(), new Path(), new Path() };
    IntStream.range(0, pop.length).forEach(i -> {
        final Color color = Color.valueOf(colors[i]);
        final Path path = stochasticTau[i];
        path.setStroke(color);
        path.setStrokeWidth(1);
        path.setClip(new Rectangle(0, 0, plot.getPrefWidth(), plot.getPrefHeight()));
    });

    final TreeMap<Double, Integer> iStochasticTau = new TreeMap<>();
    MSEIRSTest.stochasticGillespie(conf).subscribe(yt -> {
        final double x = (yt.getKey() - xl) * sx;
        iStochasticTau.put(yt.getKey(), stochasticTau[0].getElements().size());
        final long[] y = yt.getValue();
        for (int i = 0; i < y.length; i++) {
            final double yi = yh - y[i] * sy;
            final ObservableList<PathElement> path = stochasticTau[i].getElements();
            if (path.isEmpty()) {
                path.add(new MoveTo(x, yi)); // first
            } else {
                final PathElement last = path.get(path.size() - 1);
                final double y_prev = last instanceof MoveTo ? ((MoveTo) last).getY() : ((LineTo) last).getY();
                path.add(new LineTo(x, y_prev));
                path.add(new LineTo(x, yi));
            }
        }
    }, e -> LOG.error("Problem", e), () -> plot.getChildren().addAll(stochasticTau));

    final Path[] stochasticRes = { new Path(), new Path(), new Path() };
    IntStream.range(0, pop.length).forEach(i -> {
        final Color color = Color.valueOf(colors2[i]);
        final Path path = stochasticRes[i];
        path.setStroke(color);
        path.setStrokeWidth(1);
        path.setClip(new Rectangle(0, 0, plot.getPrefWidth(), plot.getPrefHeight()));
    });

    final TreeMap<Double, Integer> iStochasticRes = new TreeMap<>();
    MSEIRSTest.stochasticSellke(conf).subscribe(yt -> {
        final double x = (yt.getKey() - xl) * sx;
        iStochasticRes.put(yt.getKey(), stochasticRes[0].getElements().size());
        final long[] y = yt.getValue();
        for (int i = 0; i < y.length; i++) {
            final double yi = yh - y[i] * sy;
            final ObservableList<PathElement> path = stochasticRes[i].getElements();
            if (path.isEmpty()) {
                path.add(new MoveTo(x, yi)); // first
            } else {
                final PathElement last = path.get(path.size() - 1);
                final double y_prev = last instanceof MoveTo ? ((MoveTo) last).getY() : ((LineTo) last).getY();
                path.add(new LineTo(x, y_prev));
                path.add(new LineTo(x, yi));
            }
        }
    }, e -> LOG.error("Problem", e), () -> plot.getChildren().addAll(stochasticRes));

    // auto-scale on stage/plot resize 
    // FIXME scaling around wrong origin, use ScatterChart?
    //         xAxis.widthProperty()
    //               .addListener( (ChangeListener<Number>) ( observable,
    //                  oldValue, newValue ) ->
    //               {
    //                  final double scale = ((Double) newValue)
    //                        / plot.getPrefWidth();
    //                  plot.getChildren().filtered( n -> n instanceof Path )
    //                        .forEach( n ->
    //                        {
    //                           final Path path = (Path) n;
    //                           path.setScaleX( scale );
    //                           path.setTranslateX( (path
    //                                 .getBoundsInParent().getWidth()
    //                                 - path.getLayoutBounds().getWidth())
    //                                 / 2 );
    //                        } );
    //               } );
    //         plot.heightProperty()
    //               .addListener( (ChangeListener<Number>) ( observable,
    //                  oldValue, newValue ) ->
    //               {
    //                  final double scale = ((Double) newValue)
    //                        / plot.getPrefHeight();
    //                  plot.getChildren().filtered( n -> n instanceof Path )
    //                        .forEach( n ->
    //                        {
    //                           final Path path = (Path) n;
    //                           path.setScaleY( scale );
    //                           path.setTranslateY(
    //                                 (path.getBoundsInParent()
    //                                       .getHeight() * (scale - 1))
    //                                       / 2 );
    //                        } );
    //               } );

    final StackPane layout = new StackPane(lbl, plot);
    layout.setAlignment(Pos.TOP_CENTER);
    layout.setPadding(new Insets(50));
    layout.setStyle("-fx-background-color: rgb(35, 39, 50);");

    final Line vertiCross = new Line();
    vertiCross.setStroke(Color.SILVER);
    vertiCross.setStrokeWidth(1);
    vertiCross.setVisible(false);
    axes.getChildren().add(vertiCross);

    final Tooltip tip = new Tooltip("");
    tip.setAutoHide(false);
    tip.hide();
    axes.setOnMouseExited(ev -> tip.hide());
    axes.setOnMouseMoved(ev -> {
        final Double x = (Double) xAxis.getValueForDisplay(ev.getX());
        if (x > xAxis.getUpperBound() || x < xAxis.getLowerBound()) {
            tip.hide();
            vertiCross.setVisible(false);
            return;
        }
        final Double y = (Double) yAxis.getValueForDisplay(ev.getY());
        if (y > yAxis.getUpperBound() || y < yAxis.getLowerBound()) {
            tip.hide();
            vertiCross.setVisible(false);
            return;
        }
        final double xs = xAxis.getDisplayPosition(x);
        vertiCross.setStartX(xs);
        vertiCross.setStartY(yAxis.getDisplayPosition(0));
        vertiCross.setEndX(xs);
        vertiCross.setEndY(yAxis.getDisplayPosition(yAxis.getUpperBound()));
        vertiCross.setVisible(true);
        final int i = (iDeterministic.firstKey() > x ? iDeterministic.firstEntry()
                : iDeterministic.floorEntry(x)).getValue();
        final Object[] yi = Arrays.stream(deterministic).mapToDouble(p -> getY(p, i))
                .mapToObj(yAxis::getValueForDisplay).map(n -> DecimalUtil.toScale(n, 1)).toArray();
        final int j = (iStochasticTau.firstKey() > x ? iStochasticTau.firstEntry()
                : iStochasticTau.floorEntry(x)).getValue();
        final Object[] yj = Arrays.stream(stochasticTau).mapToDouble(p -> getY(p, j))
                .mapToObj(yAxis::getValueForDisplay).map(n -> DecimalUtil.toScale(n, 0)).toArray();
        final int k = (iStochasticRes.firstKey() > x ? iStochasticRes.firstEntry()
                : iStochasticRes.floorEntry(x)).getValue();
        final Object[] yk = Arrays.stream(stochasticRes).mapToDouble(p -> getY(p, k))
                .mapToObj(yAxis::getValueForDisplay).map(n -> DecimalUtil.toScale(n, 0)).toArray();
        final String txt = String.format("SIR(t=%.1f)\n" + "~det%s\n" + "~tau%s\n" + "~res%s", x,
                Arrays.toString(yi), Arrays.toString(yj), Arrays.toString(yk));

        tip.setText(txt);
        tip.show(axes, ev.getScreenX() - ev.getSceneX() + xs, ev.getScreenY() + 15);
    });

    try {
        stage.getIcons().add(new Image(FileUtil.toInputStream("icon.jpg")));
    } catch (final IOException e) {
        LOG.error("Problem", e);
    }
    stage.setTitle("Deterministic vs. Stochastic");
    stage.setScene(new Scene(layout, Color.rgb(35, 39, 50)));
    //         stage.setOnHidden( ev -> tip.hide() );
    stage.show();
}