Search in sources :

Example 1 with IteratorNumber

use of org.diirt.util.array.IteratorNumber in project yamcs-studio by yamcs.

the class StatisticsUtil method statisticsOf.

/**
 * Calculates data statistics, excluding NaN values.
 *
 * @param data the data
 * @return the calculated statistics
 */
public static Statistics statisticsOf(CollectionNumber data) {
    IteratorNumber iterator = data.iterator();
    if (!iterator.hasNext()) {
        return null;
    }
    int count = 0;
    double min = iterator.nextDouble();
    while (Double.isNaN(min)) {
        if (!iterator.hasNext()) {
            return null;
        } else {
            min = iterator.nextDouble();
        }
    }
    double max = min;
    double total = min;
    double totalSquare = min * min;
    count++;
    while (iterator.hasNext()) {
        double value = iterator.nextDouble();
        if (!Double.isNaN(value)) {
            if (value > max)
                max = value;
            if (value < min)
                min = value;
            total += value;
            totalSquare += value * value;
            count++;
        }
    }
    double average = total / count;
    double stdDev = Math.sqrt(totalSquare / count - average * average);
    return new StatisticsImpl(Ranges.range(min, max), count, average, stdDev);
}
Also used : IteratorNumber(org.diirt.util.array.IteratorNumber)

Example 2 with IteratorNumber

use of org.diirt.util.array.IteratorNumber in project yamcs-studio by yamcs.

the class HistogramOfFormulaFunction method calculate.

@Override
public Object calculate(List<Object> args) {
    VNumberArray numberArray = (VNumberArray) args.get(0);
    if (numberArray == null) {
        return null;
    }
    // If no change, return previous
    if (previousValue == numberArray) {
        return previousResult;
    }
    Statistics stats = StatisticsUtil.statisticsOf(numberArray.getData());
    int nBins = 100;
    Range aggregatedRange = Ranges.aggregateRange(stats.getRange(), previousXRange);
    Range xRange;
    if (Ranges.overlap(aggregatedRange, stats.getRange()) >= 0.75) {
        xRange = aggregatedRange;
    } else {
        xRange = stats.getRange();
    }
    IteratorNumber newValues = numberArray.getData().iterator();
    double minValueRange = xRange.getMinimum();
    double maxValueRange = xRange.getMaximum();
    ListNumber xBoundaries = ListNumbers.linearListFromRange(minValueRange, maxValueRange, nBins + 1);
    String unit = numberArray.getUnits();
    int[] binData = new int[nBins];
    double maxCount = 0;
    while (newValues.hasNext()) {
        double value = newValues.nextDouble();
        // Check value in range
        if (xRange.contains(value)) {
            int bin = (int) Math.floor(xRange.normalize(value) * nBins);
            if (bin == nBins) {
                bin--;
            }
            binData[bin]++;
            if (binData[bin] > maxCount) {
                maxCount = binData[bin];
            }
        }
    }
    if (previousMaxCount > maxCount && previousMaxCount < maxCount * 2.0) {
        maxCount = previousMaxCount;
    }
    previousMaxCount = maxCount;
    previousXRange = xRange;
    previousValue = numberArray;
    previousResult = newVNumberArray(new ArrayInt(binData), new ArrayInt(nBins), Arrays.asList(newDisplay(xBoundaries, unit)), numberArray, numberArray, newDisplay(0.0, 0.0, 0.0, "count", NumberFormats.format(0), maxCount, maxCount, maxCount, Double.NaN, Double.NaN));
    return previousResult;
}
Also used : VNumberArray(org.diirt.vtype.VNumberArray) ListNumber(org.diirt.util.array.ListNumber) Range(org.diirt.util.Range) ArrayInt(org.diirt.util.array.ArrayInt) Statistics(org.diirt.util.Statistics) IteratorNumber(org.diirt.util.array.IteratorNumber)

Example 3 with IteratorNumber

use of org.diirt.util.array.IteratorNumber in project org.csstudio.display.builder by kasemir.

the class ImagePlot method drawDataRGB.

/**
 * @param data_width
 *  @param data_height
 *  @param numbers
 *  @param next_rgbs
 *  @param type RGB type (RGB1, RGB2, or RGB3)
 *  @return {@link BufferedImage}, sized to match data
 */
private Object drawDataRGB(final int data_width, final int data_height, final ListNumber numbers, final ToIntFunction<IteratorNumber>[] next_rgbs, final VImageType type) {
    if (data_width <= 0 || data_height <= 0) {
        // With invalid size, cannot create a BufferedImage, not even for the error message
        return "Cannot draw image sized " + data_width + " x " + data_height;
    }
    final BufferUtil buffer = data_buffers.getBufferedImage(data_width, data_height);
    if (buffer == null)
        return "Cannot get buffer";
    final BufferedImage image = buffer.getImage();
    if (numbers.size() < data_width * data_height * 3)
        return "RGB image sized " + data_width + " x " + data_height + " received only " + numbers.size() + " data samples";
    // Using direct access to 'int' pixels in data buffer for speed. See other drawData() for details.
    final int[] data = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
    final IteratorNumber iter = numbers.iterator();
    switch(type) {
        case TYPE_RGB2:
            for (int y_times_width = 0; y_times_width < data_height * data_width; y_times_width += data_width) {
                // red
                for (int x = 0; x < data_width; ++x) data[y_times_width + x] = next_rgbs[0].applyAsInt(iter);
                ;
                // green
                for (int x = 0; x < data_width; ++x) data[y_times_width + x] |= next_rgbs[1].applyAsInt(iter);
                // blue
                for (int x = 0; x < data_width; ++x) data[y_times_width + x] |= next_rgbs[2].applyAsInt(iter);
            }
            break;
        case TYPE_RGB3:
            // red
            for (int i = 0; i < data_height * data_width; ++i) data[i] = next_rgbs[0].applyAsInt(iter);
            // green
            for (int i = 0; i < data_height * data_width; ++i) data[i] |= next_rgbs[1].applyAsInt(iter);
            // blue
            for (int i = 0; i < data_height * data_width; ++i) data[i] |= next_rgbs[2].applyAsInt(iter);
            break;
        default:
            throw new IllegalArgumentException("Image type must be an RGB type");
        // no "break;"
        case TYPE_RGB1:
            for (int i = 0; i < data_height * data_width; ++i) data[i] = next_rgbs[0].applyAsInt(iter) | next_rgbs[1].applyAsInt(iter) | next_rgbs[2].applyAsInt(iter);
    }
    return image;
}
Also used : BufferUtil(org.csstudio.javafx.BufferUtil) DataBufferInt(java.awt.image.DataBufferInt) BufferedImage(java.awt.image.BufferedImage) IteratorNumber(org.diirt.util.array.IteratorNumber)

Example 4 with IteratorNumber

use of org.diirt.util.array.IteratorNumber in project org.csstudio.display.builder by kasemir.

the class ImagePlot method drawData.

/**
 * @param data_width
 *  @param data_height
 *  @param numbers
 *  @param next_sample_func
 *  @param min
 *  @param max
 *  @param color_mapping
 *  @return {@link BufferedImage}, sized to match data or String with error message
 */
private Object drawData(final int data_width, final int data_height, final ListNumber numbers, final ToDoubleFunction<IteratorNumber> next_sample_func, double min, double max, final ColorMappingFunction color_mapping) {
    if (data_width <= 0 || data_height <= 0) {
        // With invalid size, cannot create a BufferedImage, not even for the error message
        return "Cannot draw image sized " + data_width + " x " + data_height;
    }
    final BufferUtil buffer = data_buffers.getBufferedImage(data_width, data_height);
    if (buffer == null)
        return "Cannot get buffer";
    final BufferedImage image = buffer.getImage();
    if (numbers.size() < data_width * data_height)
        return "Image sized " + data_width + " x " + data_height + " received only " + numbers.size() + " data samples";
    if (// Implies min and max being finite, not-NaN
    !(min < max)) {
        logger.log(Level.WARNING, "Invalid value range {0} .. {1}", new Object[] { min, max });
        min = 0.0;
        max = 1.0;
    }
    // Direct access to 'int' pixels in data buffer is about twice as fast as access
    // via image.setRGB(x, y, color.getRGB()),
    // which in turn is about 3x faster than drawLine or fillRect.
    // Creating a byte[] with one byte per pixel and ColorModel based on color map is fastest,
    // but only 8 bits per pixel instead of 8 bits each for R, G and B isn't enough resolution.
    // Rounding of values into 8 bits creates artifacts.
    final int[] data = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
    final IteratorNumber iter = numbers.iterator();
    int idx = 0;
    if (colorbar_axis.isLogarithmic()) {
        final double lmin = Log10.log10(min), lmax = Log10.log10(max), span = lmax - lmin;
        for (int y = 0; y < data_height; ++y) for (int x = 0; x < data_width; ++x) {
            final double sample = Log10.log10(next_sample_func.applyAsDouble(iter));
            double scaled = (sample - lmin) / span;
            if (scaled < 0.0)
                scaled = 0;
            else if (scaled > 1.0)
                scaled = 1.0;
            data[idx++] = color_mapping.getRGB(scaled);
        }
    } else {
        final double span = max - min;
        for (int y = 0; y < data_height; ++y) for (int x = 0; x < data_width; ++x) {
            final double sample = next_sample_func.applyAsDouble(iter);
            double scaled = (sample - min) / span;
            if (scaled < 0.0)
                scaled = 0;
            else if (scaled > 1.0)
                scaled = 1.0;
            data[idx++] = color_mapping.getRGB(scaled);
        }
    }
    return image;
}
Also used : BufferUtil(org.csstudio.javafx.BufferUtil) DataBufferInt(java.awt.image.DataBufferInt) BufferedImage(java.awt.image.BufferedImage) IteratorNumber(org.diirt.util.array.IteratorNumber)

Example 5 with IteratorNumber

use of org.diirt.util.array.IteratorNumber in project org.csstudio.display.builder by kasemir.

the class ImagePlot method updateImageBuffer.

/**
 * Draw all components into image buffer
 */
@Override
protected BufferedImage updateImageBuffer() {
    // Would like to use JFX WritableImage,
    // but rendering problem on Linux (sandbox.ImageScaling),
    // and no way to disable the color interpolation that 'smears'
    // the scaled image.
    // (http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8091877).
    // So image is prepared in AWT and then converted to JFX
    logger.log(Level.FINE, "updateImageBuffer");
    final Rectangle area_copy = area;
    if (area_copy.width <= 0 || area_copy.height <= 0)
        return null;
    final BufferUtil buffer = buffers.getBufferedImage(area_copy.width, area_copy.height);
    if (buffer == null)
        return null;
    final BufferedImage image = buffer.getImage();
    final Graphics2D gc = buffer.getGraphics();
    gc.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    gc.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED);
    gc.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_SPEED);
    gc.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
    // Get safe copy of the data
    // (not synchronized, i.e. width vs. data may be inconsistent,
    // but at least data won't change within this method)
    final int data_width = this.data_width, data_height = this.data_height;
    final ListNumber numbers = this.image_data;
    final boolean unsigned = this.unsigned_data;
    double min = this.min, max = this.max;
    final VImageType type = this.vimage_type;
    final ColorMappingFunction color_mapping = this.color_mapping;
    ToDoubleFunction<IteratorNumber> next_sample_func = IteratorNumber::nextDouble;
    boolean isRGB = type == VImageType.TYPE_RGB1 || type == VImageType.TYPE_RGB2 || type == VImageType.TYPE_RGB3;
    @SuppressWarnings("unchecked") final ToIntFunction<IteratorNumber>[] next_rgb = new ToIntFunction[3];
    if (numbers != null) {
        if (isRGB) {
            if (numbers instanceof ArrayShort) {
                if (unsigned) {
                    next_rgb[0] = (iter) -> getUShortForRGB(iter) << 8 & 0xFF0000;
                    next_rgb[1] = (iter) -> getUShortForRGB(iter) & 0xFF00;
                    next_rgb[2] = (iter) -> getUShortForRGB(iter) >>> 8;
                } else {
                    next_rgb[0] = (iter) -> getShortForRGB(iter) << 8 & 0xFF0000;
                    next_rgb[1] = (iter) -> getShortForRGB(iter) & 0xFF00;
                    next_rgb[2] = (iter) -> getShortForRGB(iter) >>> 8;
                }
            }
            if (numbers instanceof ArrayInt) {
                if (unsigned) {
                    next_rgb[0] = (iter) -> getUIntForRGB(iter) >>> 8 & 0xFF0000;
                    next_rgb[1] = (iter) -> getUIntForRGB(iter) >>> 16 & 0xFF00;
                    next_rgb[2] = (iter) -> getUIntForRGB(iter) >>> 24;
                } else {
                    next_rgb[0] = (iter) -> getIntForRGB(iter) >>> 8 & 0xFF0000;
                    next_rgb[1] = (iter) -> getIntForRGB(iter) >>> 16 & 0xFF00;
                    next_rgb[2] = (iter) -> getIntForRGB(iter) >>> 24;
                }
            } else {
                if (!(numbers instanceof ArrayByte))
                    logger.log(Level.WARNING, "Cannot handle rgb1 image data of type " + numbers.getClass().getName());
                if (unsigned) {
                    next_rgb[0] = (iter) -> getUByteForRGB(iter) << 16;
                    next_rgb[1] = (iter) -> getUByteForRGB(iter) << 8;
                    next_rgb[2] = (iter) -> getUByteForRGB(iter);
                } else {
                    next_rgb[0] = (iter) -> getByteForRGB(iter) << 16;
                    next_rgb[1] = (iter) -> getByteForRGB(iter) << 8;
                    next_rgb[2] = (iter) -> getByteForRGB(iter);
                }
            }
        } else // is not RGB
        {
            if (unsigned) {
                if (numbers instanceof ArrayShort)
                    next_sample_func = ImagePlot::getUnsignedShort;
                else if (numbers instanceof ArrayByte)
                    next_sample_func = ImagePlot::getUnsignedByte;
                else if (numbers instanceof ArrayInt)
                    next_sample_func = ImagePlot::getUnsignedInt;
                else
                    logger.log(Level.WARNING, "Cannot handle unsigned data of type " + numbers.getClass().getName());
            }
            if (autoscale) {
                // Compute min..max before layout of color bar
                final IteratorNumber iter = numbers.iterator();
                min = Double.MAX_VALUE;
                max = Double.NEGATIVE_INFINITY;
                while (iter.hasNext()) {
                    final double sample = next_sample_func.applyAsDouble(iter);
                    if (sample > max)
                        max = sample;
                    if (sample < min)
                        min = sample;
                }
                logger.log(Level.FINE, "Autoscale range {0} .. {1}", new Object[] { min, max });
            }
        }
    }
    // If log, min needs to be 1
    if (colorbar_axis.isLogarithmic() && min < 1.0)
        min = 1;
    colorbar_axis.setValueRange(min, max);
    if (need_layout.getAndSet(false))
        computeLayout(gc, area_copy, min, max);
    // Fill with a 'background' color
    gc.setColor(background);
    gc.fillRect(0, 0, area_copy.width, area_copy.height);
    if (numbers != null) {
        // Paint the image
        gc.setClip(image_area.x, image_area.y, image_area.width, image_area.height);
        final Object image_or_error = !isRGB ? drawData(data_width, data_height, numbers, next_sample_func, min, max, color_mapping) : drawDataRGB(data_width, data_height, numbers, next_rgb, type);
        if (image_or_error instanceof BufferedImage) {
            final BufferedImage unscaled = (BufferedImage) image_or_error;
            // Transform from full axis range into data range,
            // using the current 'zoom' state of each axis
            final LinearScreenTransform t = new LinearScreenTransform();
            AxisRange<Double> zoomed = x_axis.getValueRange();
            t.config(min_x, max_x, 0, data_width);
            // Round down .. up to always cover the image_area
            final int src_x1 = Math.max(0, (int) t.transform(zoomed.getLow()));
            final int src_x2 = Math.min(data_width, (int) (t.transform(zoomed.getHigh()) + 1));
            // Pixels of the image need to be aligned to their axis location,
            // especially when zoomed way in and the pixels are huge.
            // Turn pixel back into axis value, and then determine its destination on screen.
            final int dst_x1 = x_axis.getScreenCoord(t.inverse(src_x1));
            final int dst_x2 = x_axis.getScreenCoord(t.inverse(src_x2));
            // For Y axis, min_y == bottom == data_height
            zoomed = y_axis.getValueRange();
            t.config(min_y, max_y, data_height, 0);
            final int src_y1 = Math.max(0, (int) t.transform(zoomed.getHigh()));
            final int src_y2 = Math.min(data_height, (int) (t.transform(zoomed.getLow()) + 1));
            final int dst_y1 = y_axis.getScreenCoord(t.inverse(src_y1));
            final int dst_y2 = y_axis.getScreenCoord(t.inverse(src_y2));
            switch(interpolation) {
                case NONE:
                    gc.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
                    break;
                case INTERPOLATE:
                    gc.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
                    break;
                default:
                    // If image is smaller than screen area, show the actual pixels
                    if ((src_x2 - src_x1) < image_area.width && (src_y2 - src_y1) < image_area.height)
                        gc.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
                    else
                        // If image is larger than screen area, use best possible interpolation
                        // to avoid artifacts from statistically picking some specific nearest neighbor
                        gc.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
            }
            gc.drawImage(unscaled, dst_x1, dst_y1, dst_x2, dst_y2, src_x1, src_y1, src_x2, src_y2, /* ImageObserver */
            null);
        } else {
            gc.setColor(Color.RED);
            gc.setFont(x_axis.label_font);
            gc.drawString(Objects.toString(image_or_error), image_area.x + 10, image_area.y + 20);
        }
        gc.setClip(0, 0, area_copy.width, area_copy.height);
    }
    // Axes
    y_axis.paint(gc, image_area);
    x_axis.paint(gc, image_area);
    // Color bar
    if (colorbar_area != null) {
        final BufferedImage bar = drawColorBar(min, max, color_mapping);
        gc.drawImage(bar, colorbar_area.x, colorbar_area.y, colorbar_area.width, colorbar_area.height, null);
        colorbar_axis.paint(gc, colorbar_area);
    }
    // ROI uses X axis font
    gc.setFont(x_axis.label_font);
    for (RegionOfInterest roi : rois) drawROI(gc, roi);
    return image;
}
Also used : RegionOfInterest(org.csstudio.javafx.rtplot.RegionOfInterest) ColorMappingFunction(org.csstudio.javafx.rtplot.ColorMappingFunction) Rectangle(java.awt.Rectangle) LinearScreenTransform(org.csstudio.javafx.rtplot.internal.util.LinearScreenTransform) BufferedImage(java.awt.image.BufferedImage) Graphics2D(java.awt.Graphics2D) ListNumber(org.diirt.util.array.ListNumber) BufferUtil(org.csstudio.javafx.BufferUtil) VImageType(org.diirt.vtype.VImageType) ToIntFunction(java.util.function.ToIntFunction) ArrayByte(org.diirt.util.array.ArrayByte) ArrayInt(org.diirt.util.array.ArrayInt) ArrayShort(org.diirt.util.array.ArrayShort) IteratorNumber(org.diirt.util.array.IteratorNumber)

Aggregations

IteratorNumber (org.diirt.util.array.IteratorNumber)5 BufferedImage (java.awt.image.BufferedImage)3 BufferUtil (org.csstudio.javafx.BufferUtil)3 DataBufferInt (java.awt.image.DataBufferInt)2 ArrayInt (org.diirt.util.array.ArrayInt)2 ListNumber (org.diirt.util.array.ListNumber)2 Graphics2D (java.awt.Graphics2D)1 Rectangle (java.awt.Rectangle)1 ToIntFunction (java.util.function.ToIntFunction)1 ColorMappingFunction (org.csstudio.javafx.rtplot.ColorMappingFunction)1 RegionOfInterest (org.csstudio.javafx.rtplot.RegionOfInterest)1 LinearScreenTransform (org.csstudio.javafx.rtplot.internal.util.LinearScreenTransform)1 Range (org.diirt.util.Range)1 Statistics (org.diirt.util.Statistics)1 ArrayByte (org.diirt.util.array.ArrayByte)1 ArrayShort (org.diirt.util.array.ArrayShort)1 VImageType (org.diirt.vtype.VImageType)1 VNumberArray (org.diirt.vtype.VNumberArray)1