Harmonyos应用实例194:数据统计分析工具
·
6. 数据统计分析工具
功能简介:输入一组数据,自动计算均值、中位数、众数、方差等统计量,生成直方图。这是一个功能丰富的几何与数据工具集合,包含几何体表面积与体积计算、3D模型与展开图展示、空间点线面关系交互演示、直线方程求解与可视化、圆方程计算与直线位置关系分析,以及数据统计分析与直方图生成等功能。界面设计直观,操作流畅,支持实时参数调整和可视化反馈,是学习几何概念和数据分析的理想工具。

ArkTS代码:
@Entry
@Component
struct DataAnalyzer {
@State private data: string = '1,2,3,4,5,6,7,8,9,10'
@State private statistics: string = ''
@State private histogramData: number[] = []
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
build() {
Column() {
Text('📊 数据统计分析')
.fontSize(24).fontWeight(FontWeight.Bold)
TextInput({ placeholder: '输入数据,用逗号分隔', text: this.data })
.width('90%')
.onChange((v: string) => this.data = v)
Button('分析数据')
.onClick(() => this.analyzeData())
Canvas(this.context)
.width(300).height(200)
.onReady(() => this.drawHistogram(this.context))
Text(this.statistics)
.fontSize(14).fontColor('#666')
}
}
private analyzeData() {
// 解析数据
const numbers: number[] = this.data.split(',')
.map(s => parseFloat(s.trim()))
.filter(n => !isNaN(n))
if (numbers.length === 0) {
this.statistics = '请输入有效的数字数据'
return
}
// 计算统计量
const mean = this.calculateMean(numbers)
const median = this.calculateMedian(numbers)
const mode = this.calculateMode(numbers)
const variance = this.calculateVariance(numbers, mean)
const stdDev = Math.sqrt(variance)
const min = Math.min(...numbers)
const max = Math.max(...numbers)
const range = max - min
// 生成直方图数据
this.histogramData = this.generateHistogramData(numbers, min, max)
// 显示统计结果
const modeStr = mode[0] === -1 ? '无' : mode.join(', ')
this.statistics = `均值: ${mean.toFixed(2)} | 中位数: ${median.toFixed(2)} | 众数: ${modeStr}
方差: ${variance.toFixed(2)} | 标准差: ${stdDev.toFixed(2)} | 极差: ${range.toFixed(2)}
最小值: ${min.toFixed(2)} | 最大值: ${max.toFixed(2)} | 样本数: ${numbers.length}`
// 重绘直方图
this.drawHistogram(this.context)
}
private calculateMean(numbers: number[]): number {
const sum = numbers.reduce((acc, val) => acc + val, 0)
return sum / numbers.length
}
private calculateMedian(numbers: number[]): number {
const sorted = [...numbers].sort((a, b) => a - b)
const mid = Math.floor(sorted.length / 2)
if (sorted.length % 2 === 0) {
return (sorted[mid - 1] + sorted[mid]) / 2
} else {
return sorted[mid]
}
}
private calculateMode(numbers: number[]): number[] {
const frequency: Map<number, number> = new Map()
numbers.forEach(num => {
frequency.set(num, (frequency.get(num) || 0) + 1)
})
const values: number[] = Array.from(frequency.values())
let maxFreq: number = 0
for (let i = 0; i < values.length; i++) {
if (values[i] > maxFreq) {
maxFreq = values[i]
}
}
if (maxFreq === 1) return [-1]
const result: number[] = []
frequency.forEach((freq, num) => {
if (freq === maxFreq) {
result.push(num)
}
})
return result
}
private calculateVariance(numbers: number[], mean: number): number {
const sumSquaredDiff = numbers.reduce((acc, val) => acc + Math.pow(val - mean, 2), 0)
return sumSquaredDiff / numbers.length
}
private generateHistogramData(numbers: number[], min: number, max: number): number[] {
const binCount = 10
const binWidth = (max - min) / binCount
const bins: number[] = new Array(binCount).fill(0)
numbers.forEach(num => {
const binIndex = Math.min(Math.floor((num - min) / binWidth), binCount - 1)
bins[binIndex]++
})
return bins
}
private drawHistogram(ctx: CanvasRenderingContext2D) {
const width = 300
const height = 200
// 清空画布
ctx.clearRect(0, 0, width, height)
ctx.fillStyle = '#F5F5F5'
ctx.fillRect(0, 0, width, height)
if (this.histogramData.length === 0) return
// 绘制直方图
const maxCount = Math.max(...this.histogramData)
const barWidth = width / this.histogramData.length
this.histogramData.forEach((count, index) => {
const barHeight = (count / maxCount) * (height - 40)
const x = index * barWidth
const y = height - barHeight - 20
// 绘制柱子
ctx.fillStyle = '#2196F3'
ctx.fillRect(x + 2, y, barWidth - 4, barHeight)
// 绘制数值
if (count > 0) {
ctx.fillStyle = '#333333'
ctx.font = '10px sans-serif'
ctx.fillText(count.toString(), x + barWidth / 2 - 3, y - 5)
}
})
// 绘制坐标轴
ctx.strokeStyle = '#666666'
ctx.lineWidth = 1
ctx.beginPath()
ctx.moveTo(0, height - 20)
ctx.lineTo(width, height - 20)
ctx.stroke()
}
}
更多推荐

所有评论(0)