package scientific.matplot
import std.unittest.*
import std.unittest.testmacro.*
import scientific.numbers.*
import scientific.linear.*
import scientific.stats.random.*
import scientific.stats.normal.*
/* Type for x: Float64 */
foreign func c_boxplot(x: CPointer<Unit>, x_len: Int64): CPointer<Unit>
foreign func c_boxplot_2d(x: CPointer<Unit>, row: Int64, col: Int64): CPointer<Unit>
foreign func c_boxplot_str(x: CPointer<Unit>, groups: CPointer<CString>, len: Int64): CPointer<Unit>
foreign func c_box_style(box: CPointer<Unit>, style: CString): CPointer<Unit>
public class BoxChart {
var ptr: CPointer<Unit> = CPointer<Unit>()
init(ptr: CPointer<Unit>) {
this.ptr = ptr
}
public func box_style(style: BoxStyleOption) {
var cstr_style = unsafe { LibC.mallocCString(style.toString()) }
this.ptr = unsafe { c_box_style(this.ptr, cstr_style) }
unsafe { LibC.free(cstr_style) }
return this
}
}
public enum BoxStyleOption {
| outline // unfilled / dashed whiskers
| filled // filled / solid whiskers
| violin // show data distribution
func toString(): String {
return match (this) {
case outline => "outline"
case filled => "filled"
case violin => "violin"
}
}
}
public func boxplot(x: Vector<Float64>) {
let size = x.size()
let handle = unsafe { c_boxplot(x.ptr, size) }
return BoxChart(handle)
}
public func boxplot(x: Matrix<Float64>) {
let row = x.getRows()
let col = x.getCols()
let handle = unsafe { c_boxplot_2d(x.ptr, row, col) }
return BoxChart(handle)
}
public func boxplot(x: Vector<Float64>, groups: Array<String>) {
if (x.size() != groups.size) {
throw IllegalArgumentException("boxplot: size of data and groups does not match")
}
var a = unsafe { malloc(UIntNative(8 * x.size())) }
var group_ptr = CPointer<CString>(a)
for (i in 0..x.size()) {
var cstr_group = unsafe { LibC.mallocCString(groups[i]) }
unsafe { group_ptr.write(i, cstr_group) }
unsafe { LibC.free(cstr_group) }
}
let handle = unsafe { c_boxplot_str(x.ptr, group_ptr, x.size() ) }
return BoxChart(handle)
}
public func testBox1() {
print(" - testBox1\n")
let mpg = vector<Float64>([
18.0, 15.0, 18.0, 16.0, 17.0, 15.0, 14.0, 14.0, 14.0, 15.0, 15.0, 14.0,
15.0, 14.0, 24.0, 22.0, 18.0, 21.0, 27.0, 26.0, 25.0, 24.0, 25.0, 26.0,
21.0, 10.0, 10.0, 11.0, 9.0, 28.0, 25.0, 25.0, 26.0, 27.0, 17.5, 16.0,
15.5, 14.5, 22.0, 22.0, 24.0, 22.5, 29.0, 24.5, 29.0, 33.0, 20.0, 18.0,
18.5, 17.5, 29.5, 32.0, 28.0, 26.5, 20.0, 13.0, 19.0, 19.0, 16.5, 16.5,
13.0, 13.0, 13.0, 28.0, 27.0, 34.0, 31.0, 29.0, 27.0, 24.0, 23.0, 36.0,
37.0, 31.0, 38.0, 36.0, 36.0, 36.0, 34.0, 38.0, 32.0, 38.0, 25.0, 38.0,
26.0, 22.0, 32.0, 36.0, 27.0, 27.0, 44.0, 32.0, 28.0, 31.0])
boxplot(mpg)
xlabel("All Vehicles")
ylabel("Miles per Gallon (MPG)")
title("Miles per Gallon for All Vehicles")
save("./tests/imgs/boxplot/boxchart_1.svg", "svg")
clear()
}
public func testBox2() {
print(" - testBox2\n")
let mpg = vector<Float64>([
18.0, 15.0, 18.0, 16.0, 17.0, 15.0, 14.0, 14.0, 14.0, 15.0, 15.0, 14.0,
15.0, 14.0, 24.0, 22.0, 18.0, 21.0, 27.0, 26.0, 25.0, 24.0, 25.0, 26.0,
21.0, 10.0, 10.0, 11.0, 9.0, 28.0, 25.0, 25.0, 26.0, 27.0, 17.5, 16.0,
15.5, 14.5, 22.0, 22.0, 24.0, 22.5, 29.0, 24.5, 29.0, 33.0, 20.0, 18.0,
18.5, 17.5, 29.5, 32.0, 28.0, 26.5, 20.0, 13.0, 19.0, 19.0, 16.5, 16.5,
13.0, 13.0, 13.0, 28.0, 27.0, 34.0, 31.0, 29.0, 27.0, 24.0, 23.0, 36.0,
37.0, 31.0, 38.0, 36.0, 36.0, 36.0, 34.0, 38.0, 32.0, 38.0, 25.0, 38.0,
26.0, 22.0, 32.0, 36.0, 27.0, 27.0, 44.0, 32.0, 28.0, 31.0])
let origin = [
"USA", "USA", "USA", "USA", "USA", "USA", "USA",
"USA", "USA", "USA", "USA", "USA", "USA", "USA",
"Japan", "USA", "USA", "USA", "Japan", "Germany", "France",
"Germany", "Sweden", "Germany", "USA", "USA", "USA", "USA",
"USA", "Italy", "Germany", "USA", "USA", "France", "USA",
"USA", "USA", "USA", "USA", "USA", "USA", "USA",
"USA", "USA", "Germany", "Japan", "USA", "USA", "USA",
"USA", "Germany", "Japan", "Japan", "USA", "Sweden", "USA",
"France", "Japan", "Germany", "USA", "USA", "USA", "USA",
"USA", "USA", "USA", "USA", "USA", "USA", "USA",
"USA", "Germany", "Japan", "Japan", "USA", "USA", "Japan",
"Japan", "Japan", "Japan", "Japan", "Japan", "USA", "USA",
"USA", "USA", "Japan", "USA", "USA", "USA", "Germany",
"USA", "USA", "USA"
]
boxplot(mpg, origin)
xlabel("All Vehicles")
ylabel("Miles per Gallon (MPG)")
title("Miles per Gallon for All Vehicles")
save("./tests/imgs/boxplot/boxchart_2.svg", "svg")
clear()
}
public func testBox3() {
print(" - testBox3\n")
var m: Random = Random(0)
let x = randn(m, 25, 100, 0.0, 1.0)
subplot(2,1,0)
boxplot(x)
subplot(2,1,1)
let box = boxplot(x)
box.box_style(outline)
save("./tests/imgs/boxplot/boxchart_3.svg", "svg")
clear()
}
public func testBoxChart() {
print(" + testBoxChart\n")
testBox1()
testBox2()
testBox3()
}