Skip to content

Commit 2866fd8

Browse files
committed
fix: moved functions to utils to avoid exporting from lib
1 parent bd4a02c commit 2866fd8

2 files changed

Lines changed: 106 additions & 105 deletions

File tree

src/index.ts

Lines changed: 1 addition & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,4 @@
1-
import * as asciichart from "asciichart";
2-
3-
import { AsciiChartOptions, PDFEstimation } from "./types";
4-
import { smooth, widenData } from "./utils";
5-
6-
/**
7-
* Estimate the probability density function (PDF) from raw data using a histogram.
8-
*
9-
* If the data are discrete (all integer values) then a binWidth of 1 is used.
10-
*
11-
* @param data - Raw data points.
12-
* @param numBins - Number of bins for the histogram (optional).
13-
* @returns An object containing binCenters, estimated pdf values, and the overall x-range.
14-
*/
15-
function estimatePDF(data: number[], numBins?: number): PDFEstimation {
16-
const isDiscrete: boolean = data.every((v) => Number.isInteger(v));
17-
let dataMin = Math.min(...data);
18-
let dataMax = Math.max(...data);
19-
20-
let binWidth: number;
21-
let bins: number[];
22-
23-
if (isDiscrete) {
24-
dataMin = Math.floor(dataMin);
25-
dataMax = Math.ceil(dataMax);
26-
numBins = dataMax - dataMin + 1;
27-
binWidth = 1;
28-
bins = new Array(numBins).fill(0);
29-
} else {
30-
numBins = numBins || 20;
31-
binWidth = (dataMax - dataMin) / numBins;
32-
bins = new Array(numBins).fill(0);
33-
}
34-
35-
// Count data points in each bin.
36-
data.forEach((value) => {
37-
let binIndex = Math.floor((value - dataMin) / binWidth);
38-
if (binIndex < 0) binIndex = 0;
39-
else if (binIndex >= bins.length) binIndex = bins.length - 1;
40-
bins[binIndex]++;
41-
});
42-
43-
const totalCount = data.length;
44-
// Convert counts into density: density = count / (totalCount * binWidth)
45-
let pdf = bins.map((count) => count / (totalCount * binWidth));
46-
47-
// Smooth the PDF for better visual appearance.
48-
pdf = smooth(pdf, 3);
49-
50-
// Compute bin centers (to be used as x-axis tick marks).
51-
const binCenters: number[] = Array.from(
52-
{ length: numBins },
53-
(_, i) => dataMin + (i + 0.5) * binWidth
54-
);
55-
56-
return { binCenters, pdf, xMin: dataMin, xMax: dataMax };
57-
}
58-
59-
/**
60-
* Plot an array of y-values using asciichart with custom x-axis labels.
61-
*
62-
* An optional xLabelOffset (number of spaces) can be provided via options to shift the left x-axis label.
63-
*
64-
* @param dataValues - The y-values (e.g., estimated PDF values).
65-
* @param xMin - The minimum x value for labeling.
66-
* @param xMax - The maximum x value for labeling.
67-
* @param options - Additional options for asciichart.
68-
*/
69-
function plotWithXAxis(
70-
dataValues: number[],
71-
xMin: number,
72-
xMax: number,
73-
options: AsciiChartOptions = {}
74-
): void {
75-
// Set fixed y-axis limits for a tighter plot.
76-
const yMax: number = Math.max(...dataValues) * 1.05;
77-
const plotOptions = Object.assign(
78-
{
79-
height: 15,
80-
min: 0,
81-
max: yMax,
82-
},
83-
options
84-
);
85-
86-
// Create and display the plot.
87-
const chart = asciichart.plot(dataValues, plotOptions);
88-
console.log(chart);
89-
90-
// Determine the width of the chart.
91-
const chartLines = chart.split("\n");
92-
const chartWidth = Math.max(...chartLines.map((line) => line.length));
93-
94-
// Use the xLabelOffset option (defaulting to 0) to add extra spaces before the left label.
95-
const xLabelOffset: number = options.xLabelOffset || 0;
96-
97-
// Build an x-axis label line.
98-
const leftLabel = " ".repeat(xLabelOffset) + xMin.toFixed(1);
99-
const rightLabel = xMax.toFixed(1);
100-
let labelLine = " ".repeat(chartWidth);
101-
labelLine = leftLabel + labelLine.slice(leftLabel.length);
102-
const rightStart = chartWidth - rightLabel.length;
103-
labelLine = labelLine.slice(0, rightStart) + rightLabel;
104-
console.log(labelLine);
105-
}
1+
import { estimatePDF, plotWithXAxis, widenData } from "./utils";
1062

1073
/**
1084
* Demonstrate PDF estimation and plotting for a given dataset.

src/utils.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import * as asciichart from "asciichart";
2+
3+
import { AsciiChartOptions, PDFEstimation } from "./types";
4+
15
/**
26
* Smooth an array of numbers using a simple moving average filter.
37
* Default window size is 3.
@@ -54,3 +58,104 @@ export function widenData(data: number[], factor: number = 1): number[] {
5458
widened.push(data[data.length - 1]);
5559
return widened;
5660
}
61+
62+
/**
63+
* Estimate the probability density function (PDF) from raw data using a histogram.
64+
*
65+
* If the data are discrete (all integer values) then a binWidth of 1 is used.
66+
*
67+
* @param data - Raw data points.
68+
* @param numBins - Number of bins for the histogram (optional).
69+
* @returns An object containing binCenters, estimated pdf values, and the overall x-range.
70+
*/
71+
export function estimatePDF(data: number[], numBins?: number): PDFEstimation {
72+
const isDiscrete: boolean = data.every((v) => Number.isInteger(v));
73+
let dataMin = Math.min(...data);
74+
let dataMax = Math.max(...data);
75+
76+
let binWidth: number;
77+
let bins: number[];
78+
79+
if (isDiscrete) {
80+
dataMin = Math.floor(dataMin);
81+
dataMax = Math.ceil(dataMax);
82+
numBins = dataMax - dataMin + 1;
83+
binWidth = 1;
84+
bins = new Array(numBins).fill(0);
85+
} else {
86+
numBins = numBins || 20;
87+
binWidth = (dataMax - dataMin) / numBins;
88+
bins = new Array(numBins).fill(0);
89+
}
90+
91+
// Count data points in each bin.
92+
data.forEach((value) => {
93+
let binIndex = Math.floor((value - dataMin) / binWidth);
94+
if (binIndex < 0) binIndex = 0;
95+
else if (binIndex >= bins.length) binIndex = bins.length - 1;
96+
bins[binIndex]++;
97+
});
98+
99+
const totalCount = data.length;
100+
// Convert counts into density: density = count / (totalCount * binWidth)
101+
let pdf = bins.map((count) => count / (totalCount * binWidth));
102+
103+
// Smooth the PDF for better visual appearance.
104+
pdf = smooth(pdf, 3);
105+
106+
// Compute bin centers (to be used as x-axis tick marks).
107+
const binCenters: number[] = Array.from(
108+
{ length: numBins },
109+
(_, i) => dataMin + (i + 0.5) * binWidth
110+
);
111+
112+
return { binCenters, pdf, xMin: dataMin, xMax: dataMax };
113+
}
114+
115+
/**
116+
* Plot an array of y-values using asciichart with custom x-axis labels.
117+
*
118+
* An optional xLabelOffset (number of spaces) can be provided via options to shift the left x-axis label.
119+
*
120+
* @param dataValues - The y-values (e.g., estimated PDF values).
121+
* @param xMin - The minimum x value for labeling.
122+
* @param xMax - The maximum x value for labeling.
123+
* @param options - Additional options for asciichart.
124+
*/
125+
export function plotWithXAxis(
126+
dataValues: number[],
127+
xMin: number,
128+
xMax: number,
129+
options: AsciiChartOptions = {}
130+
): void {
131+
// Set fixed y-axis limits for a tighter plot.
132+
const yMax: number = Math.max(...dataValues) * 1.05;
133+
const plotOptions = Object.assign(
134+
{
135+
height: 15,
136+
min: 0,
137+
max: yMax,
138+
},
139+
options
140+
);
141+
142+
// Create and display the plot.
143+
const chart = asciichart.plot(dataValues, plotOptions);
144+
console.log(chart);
145+
146+
// Determine the width of the chart.
147+
const chartLines = chart.split("\n");
148+
const chartWidth = Math.max(...chartLines.map((line) => line.length));
149+
150+
// Use the xLabelOffset option (defaulting to 0) to add extra spaces before the left label.
151+
const xLabelOffset: number = options.xLabelOffset || 0;
152+
153+
// Build an x-axis label line.
154+
const leftLabel = " ".repeat(xLabelOffset) + xMin.toFixed(1);
155+
const rightLabel = xMax.toFixed(1);
156+
let labelLine = " ".repeat(chartWidth);
157+
labelLine = leftLabel + labelLine.slice(leftLabel.length);
158+
const rightStart = chartWidth - rightLabel.length;
159+
labelLine = labelLine.slice(0, rightStart) + rightLabel;
160+
console.log(labelLine);
161+
}

0 commit comments

Comments
 (0)