package com.github.pfichtner.jrunalyser.base.stat;
import java.util.Arrays;
import java.util.Collection;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Range;
import com.google.common.primitives.Doubles;
public final class Boxplot {
private final double[] values;
public static class InterquatileRange {
private final double lower;
private final double upper;
public InterquatileRange(double lower, double upper) {
this.lower = lower;
this.upper = upper;
}
public double getLower() {
return this.lower;
}
public double getUpper() {
return this.upper;
}
@Override
public String toString() {
return "InterquatileRange [lower=" + this.lower + ", upper="
+ this.upper + "]";
}
}
public Boxplot(Double[] values) {
this(Doubles.toArray(Arrays.asList(values)));
}
public Boxplot(Collection<Double> values) {
this(Doubles.toArray(values));
}
public Boxplot(double[] values) {
this.values = sort(values.clone());
}
private static double[] sort(double[] values) {
Arrays.sort(values);
return values;
}
public double median() {
return m(2);
}
public double q1() {
return m(4);
}
public double q3() {
return m(1.25);
}
private double m(double q) {
int c = (int) (this.values.length / q);
double m = this.values[c];
return this.values.length % 2 == 0 ? (this.values[c - 1] + m) / 2 : m;
}
public InterquatileRange innerFences() {
return fences(1.5);
}
public InterquatileRange outerFences() {
return fences(3.0);
}
public InterquatileRange fences(double m) {
double q3 = q3();
double q1 = q1();
double iqr = (q3 - q1) * m;
return new InterquatileRange(q1 - iqr, q3 + iqr);
}
public double[] getValues() {
return this.values.clone();
}
public double[] getValues(InterquatileRange fence) {
return filter(Range.closed(Double.valueOf(fence.getLower()),
Double.valueOf(fence.getUpper())));
}
public double[] filter(Predicate<Double> p) {
return Doubles.toArray(FluentIterable.from(Doubles.asList(this.values))
.filter(p).toList());
}
}