class JQuickHistogram {

    private final boolean inclusive = true;
    private int constraintHeight = 0;
    private int constraintWidth = 0;
    private JPanel panel;
    //Data
    private List<Double> data;
    private Double minValue;
    private Double maxValue;
    private Double minRange;
    private Double maxRange;

    public JQuickHistogram() {
        clear();
    }

    public void clear() {
        data = new ArrayList<>();
        minValue = Double.MAX_VALUE;
        maxValue = Double.NEGATIVE_INFINITY;
    }

    public void addData(Object data) {<FILL_FUNCTION_BODY>}

    public void addData(Double data) {
        this.data.add(data);
        minValue = Math.min(minValue, data);
        maxValue = Math.max(maxValue, data);
        minRange = minValue;
        maxRange = maxValue;
    }

    public void sortData() {
        Collections.sort(data);
    }

    public void setLowerBound(Double lowerBound) {
        this.minRange = lowerBound;
    }

    public void setUpperBound(Double upperBound) {
        this.maxRange = upperBound;
    }

    public JPanel getPanel() {
        if (panel == null) {
            panel = new JQuickHistogramPanel(this);
        }
        return panel;
    }

    public void setConstraintHeight(int constraintHeight) {
        this.constraintHeight = constraintHeight;
        panel.setPreferredSize(new Dimension(constraintWidth, constraintHeight));
        panel.setMinimumSize(new Dimension(constraintWidth, constraintHeight));
    }

    public void setConstraintWidth(int constraintWidth) {
        this.constraintWidth = constraintWidth;
        panel.setPreferredSize(new Dimension(constraintWidth, constraintHeight));
        panel.setMinimumSize(new Dimension(constraintWidth, constraintHeight));
    }

    public int countValues() {
        return data.size();
    }

    public int countInRange() {
        int res = 0;
        for (int i = 0; i < data.size(); i++) {
            Double d = data.get(i);
            if ((inclusive && d >= minRange && d <= maxRange) || (!inclusive && d > minRange && d < maxRange)) {
                res++;
            }
        }
        return res;
    }

    public double getAverage() {
        double res = 0;
        for (int i = 0; i < data.size(); i++) {
            double d = data.get(i);
            res += d;
        }
        return res /= data.size();
    }

    public double getAverageInRange() {
        double res = 0;
        int c = 0;
        for (int i = 0; i < data.size(); i++) {
            double d = data.get(i);
            if ((inclusive && d >= minRange && d <= maxRange) || (!inclusive && d > minRange && d < maxRange)) {
                res += d;
                c++;
            }
        }
        return res /= c;
    }

    public double getMedian() {
        return data.get((data.size() + 1) / 2);
    }

    public double getMedianInRange() {
        int median = (countInRange() + 1) / 2;
        for (int i = 0; i < data.size(); i++) {
            double d = data.get(i);
            if ((inclusive && d >= minRange && d <= maxRange) || (!inclusive && d > minRange && d < maxRange)) {
                if (median-- == 0) {
                    return d;
                }
            }
        }
        return -1.;
    }

    private static class JQuickHistogramPanel extends JPanel {

        private final Color fillColor = new Color(0xCFD2D3);
        private final Color fillInRangeColor = new Color(0x3B4042);
        private final JQuickHistogram histogram;
        private int currentHeight = 0;
        private int currentWidth = 0;

        public JQuickHistogramPanel(JQuickHistogram histogram) {
            this.histogram = histogram;
            setOpaque(false);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            setCurrentDimension();
            Graphics2D g2d = (Graphics2D) g;
            g2d.translate(0, currentHeight);
            g2d.scale(1, -1);
            drawHisto(g2d);
            g2d.dispose();
        }

        private void drawHisto(Graphics2D g2d) {

            if (histogram.minRange == null || histogram.maxRange == null) {
                return;
            }

            int dataSize = histogram.data.size();
            if (dataSize < currentWidth) {
                int rectWidth = (int) (currentWidth / (float) dataSize);
                int leftover = currentWidth - rectWidth * dataSize;
                int xPosition = 0;
                for (int i = 0; i < dataSize; i++) {
                    Double data = histogram.data.get(i);
                    int rectangleWidth = rectWidth + (leftover > 0 ? 1 : 0);
                    leftover--;
                    int rectangleHeight =
                        (int) ((data - histogram.minValue) / (histogram.maxValue - histogram.minValue) * currentHeight);
                    if (data >= histogram.minRange && data <= histogram.maxRange) {
                        g2d.setColor(fillInRangeColor);
                    } else {
                        g2d.setColor(fillColor);
                    }
                    g2d.fillRect(xPosition, 0, rectangleWidth, rectangleHeight);

                    xPosition += rectangleWidth;
                }
            } else {
                int xPosition = 0;
                int sizeOfSmallSublists = dataSize / currentWidth;
                int sizeOfLargeSublists = sizeOfSmallSublists + 1;
                int numberOfLargeSublists = dataSize % currentWidth;
                int numberOfSmallSublists = currentWidth - numberOfLargeSublists;

                int numberOfElementsHandled = 0;
                for (int i = 0; i < currentWidth; i++) {
                    int size = i < numberOfSmallSublists ? sizeOfSmallSublists : sizeOfLargeSublists;
                    double average = 0.0;
                    for (int j = 0; j < size; j++) {
                        Double d = histogram.data.get(numberOfElementsHandled++);
                        average += d;
                    }
                    average /= size;
                    int rectangleHeight =
                        (int) ((average - histogram.minValue) / (histogram.maxValue - histogram.minValue) *
                            currentHeight);

                    if (average >= histogram.minRange && average <= histogram.maxRange) {
                        g2d.setColor(fillInRangeColor);
                    } else {
                        g2d.setColor(fillColor);
                    }
                    g2d.fillRect(xPosition, 0, 1, rectangleHeight);
                    xPosition++;
                }
            }
        }

        private void setCurrentDimension() {
            currentHeight = (histogram.constraintHeight > 0 ? histogram.constraintHeight : getHeight());
            currentWidth = (histogram.constraintWidth > 0 ? histogram.constraintWidth : getWidth());
        }
    }
}

        if (data instanceof Double) {
            addData((Double) data);
        } else if (data instanceof Integer) {
            addData(((Integer) data).doubleValue());
        } else if (data instanceof Float) {
            addData(((Float) data).doubleValue());
        } else if (data instanceof Long) {
            addData(((Long) data).doubleValue());
        }
    
<no_super_class>