import { Box, Text } from "ink";
import { zip } from "../../utils";
type ItemStats = {
name: string;
values: number[];
};
const PADDING = 10;
export function WhiskerPlot(props: { items: ItemStats[] }) {
const stats = props.items.map((item) => getItemStats(item.values));
const allLowerWhisker = Math.min(...stats.map((stat) => stat.lowerWhisker));
const allUpperWhisker = Math.max(...stats.map((stat) => stat.upperWhisker));
const chartHeight = allUpperWhisker - allLowerWhisker;
const maxNameLength = Math.max(
...props.items.map((item) => item.name.length)
);
const scale = scaleValue(
(process.stdout.columns - maxNameLength - PADDING) / chartHeight
);
return (
{zip(stats, props.items).map(([stat, scenario]) => (
{" ".repeat(maxNameLength - scenario.name.length + 1)}
{scenario.name}{" "}
))}
);
}
type ItemWhiskerStats = {
min: number;
max: number;
median: number;
q1: number;
q3: number;
lowerWhisker: number;
upperWhisker: number;
};
function getItemStats(values: number[]): ItemWhiskerStats {
const sortedValues = values.sort((a, b) => a - b);
const min = sortedValues[0];
const max = sortedValues[sortedValues.length - 1];
const median = sortedValues[Math.floor(sortedValues.length / 2)];
const q1 = sortedValues[Math.floor(sortedValues.length / 4)];
const q3 = sortedValues[Math.floor((sortedValues.length * 3) / 4)];
const iqr = q3 - q1;
const lowerWhisker = Math.max(min, q1 - 1.5 * iqr);
const upperWhisker = Math.min(max, q3 + 1.5 * iqr);
return { min, max, median, q1, q3, lowerWhisker, upperWhisker };
}
function ItemWhisker(props: {
stats: ItemWhiskerStats;
leftOffset: number;
scale: (value: number) => number;
}) {
const {
stats: { q1, q3, lowerWhisker, median, upperWhisker },
scale,
leftOffset,
} = props;
return (
├
{"─".repeat(scale(q1 - lowerWhisker))}
{scale(median - q1) - 1 > 0 && (
{" ".repeat(scale(median - q1) - 1)}│
)}
{"─".repeat(scale(upperWhisker - q3))}
┤
);
}
const scaleValue = (scale: number) => (value: number) =>
Math.round(value * scale);
// const sampleData = [
// { name: "A", values: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] },
// { name: "B", values: [1, 2, 2, 2, 4, 3] },
// ];
// render();