大數據(big data),指無法在一定時間范圍內用常規軟件工具進行捕捉、管理和處理的數據集合,是需要新處理模式才能具有更強的決策力、洞察發現力和流程優化能力的海量、高增長率和多樣化的信息資產。
大數據技術的戰略意義不在於掌握龐大的數據信息,而在於對這些含有意義的數據進行專業化處理。換而言之,如果把大數據比作一種產業,那么這種產業實現盈利的關鍵,在於提高對數據的“加工能力”,通過“加工”實現數據的“增值”。
前言
今年大數據行業火爆異常,大數據的實用點之一在於數據的統計和加工實現數據的“增值”,方便人們從大量的數據統計中得出結論。
對於一個iOS開發程序猿來說不是專門搞大數據開發的,似乎沒有多大關系,但后續iOS開發中,各類APP中必然會加入統計表格的形式展示數據,相對於傳統的列表形式+各類查詢顯示,表格形式直觀、簡潔、通俗易懂,分析更透徹,必然會成為搶手貨。
本文介紹一下簡易的柱狀圖、折線圖、扇形圖三種統計圖的制作,希望能幫助到大家
坐標系
利用CAShapeLayer和UIBezierPath繪制坐標系,坐標系中需要繪制的部分如下圖所示:

需要繪制的部分有原點、x坐標軸、y坐標軸、坐標軸末尾的箭頭和坐標軸上的標度。需要計算位置和長度,需要根據所在頁面的大小計算坐標系的位置和大小。
這里給出代碼如下:
CAShapeLayer *layer = [CAShapeLayer layer];
UIBezierPath *path = [UIBezierPath bezierPath];
//坐標軸原點
CGPoint rPoint = CGPointMake(1.3*margin, self.zzHeight-margin);
//畫y軸
[path moveToPoint:rPoint];
[path addLineToPoint:CGPointMake(1.3*margin, margin)];
//畫y軸的箭頭
[path moveToPoint:CGPointMake(1.3*margin, margin)];
[path addLineToPoint:CGPointMake(1.3*margin-5, margin+5)];
[path moveToPoint:CGPointMake(1.3*margin, margin)];
[path addLineToPoint:CGPointMake(1.3*margin+5, margin+5)];
//畫x軸
[path moveToPoint:rPoint];
[path addLineToPoint:CGPointMake(self.zzWidth-0.8*margin, self.zzHeight-margin)];
//畫x軸的箭頭
[path moveToPoint:CGPointMake(self.zzWidth-0.8*margin, self.zzHeight-margin)];
[path addLineToPoint:CGPointMake(self.zzWidth-0.8*margin-5, self.zzHeight-margin-5)];
[path moveToPoint:CGPointMake(self.zzWidth-0.8*margin, self.zzHeight-margin)];
[path addLineToPoint:CGPointMake(self.zzWidth-0.8*margin-5, self.zzHeight-margin+5)];
//畫x軸上的標度
for (int i=0; i<x_itemArr.count; i++) {
[path moveToPoint:CGPointMake(1.3*margin+(self.zzWidth-2*margin)/(x_itemArr.count+1)*(i+1), self.zzHeight-margin)];
[path addLineToPoint:CGPointMake(1.3*margin+(self.zzWidth-2*margin)/(x_itemArr.count+1)*(i+1), self.zzHeight-margin-3)];
}
//畫y軸上的標度
for (int i=0; i<10; i++) {
[path moveToPoint:CGPointMake(1.3*margin, margin+(self.zzHeight-2*margin)/11*(i+1))];
[path addLineToPoint:CGPointMake(1.3*margin+3, margin+(self.zzHeight-2*margin)/11*(i+1))];
}
layer.path = path.CGPath;
layer.fillColor = [UIColor clearColor].CGColor;
layer.strokeColor = [UIColor blackColor].CGColor;
layer.lineWidth = 2.0;
[self.layer addSublayer:layer];
//給y軸加標注
for (int i=0; i<11; i++) {
CGFloat yLHeight = (self.zzHeight-2*margin)/11 <= 20 ? (self.zzHeight-2*margin)/11 : 20;
CGFloat yLWidth = yLHeight*2 >= 25 ? 25 : yLHeight*2;
CGFloat size = (self.zzHeight-2*margin)/11 <= 20 ? 7 : 12;
UILabel *lab = [[UILabel alloc] initWithFrame:CGRectMake(1.3*margin-yLWidth-5, margin+(self.zzHeight-2*margin)/11*(10-i+0.5), yLWidth, yLHeight)];
lab.text = [NSString stringWithFormat:@"%d", 10*i];
lab.textColor = [UIColor blackColor];
lab.font = [UIFont boldSystemFontOfSize:size];
lab.textAlignment = NSTextAlignmentCenter;
[self addSubview:lab];
}
柱狀圖
在繪制坐標系的基礎上,繪制柱狀圖的原理非常簡單,根據x軸的坐標,計算每條柱的高度。
這里需要注意:
提供的數據需要轉化為自己設定的y軸的刻度單位計算出的高度。另外,柱狀圖需要占用x軸的寬度,所以柱子的位置需要好好考慮一下放在x軸的什么位置。
代碼如下:
//畫柱狀圖
for (int i=0; i<x_itemArr.count; i++) {
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(1.3*margin+(self.zzWidth-2*margin)/(x_itemArr.count+1)*(i+0.7), self.zzHeight-margin-(self.zzHeight-2*margin)/11*[y_itemArr[i] floatValue]/10, 0.6*((self.zzWidth-2*margin)/(x_itemArr.count+1)), (self.zzHeight-2*margin)/11*[y_itemArr[i] floatValue]/10-1)];
CAShapeLayer *layer = [CAShapeLayer layer];
layer.path = path.CGPath;
layer.fillColor = zzRandomColor.CGColor;
layer.strokeColor = [UIColor clearColor].CGColor;
[self.layer addSublayer:layer];
}
//給x軸加標注
for (int i=0; i<x_itemArr.count; i++) {
CGFloat xLWidth = ((self.zzWidth-2*margin)/(x_itemArr.count+1)) <= 25 ? ((self.zzWidth-2*margin)/(x_itemArr.count+1)) : 25;
UILabel *lab = [[UILabel alloc] initWithFrame:CGRectMake(1.3*margin+(self.zzWidth-2*margin)/(x_itemArr.count+1)*(i+1)-xLWidth/2, self.zzHeight-margin, xLWidth, 20)];
lab.text = x_itemArr[i];
lab.textColor = [UIColor blackColor];
lab.adjustsFontSizeToFitWidth = YES;
lab.textAlignment = NSTextAlignmentCenter;
[self addSubview:lab];
}

折線圖
在坐標系的基礎上,計算繪制對應y軸上的點,然后從第一個點開始,依次連接到最后一個點,可以直線連接,或者用貝塞爾曲線繪制,具體看實際情況實現。
代碼如下:
//開始點
CGPoint startPoint = CGPointMake(1.3*margin+(self.zzWidth-2*margin)/(x_itemArr.count+1), self.zzHeight-margin-(self.zzHeight-2*margin)/11*[y_itemArr[0] floatValue]/10);
//結束點
CGPoint endPoint;
for (int i=0; i<x_itemArr.count; i++) {
endPoint = CGPointMake(1.3*margin+(self.zzWidth-2*margin)/(x_itemArr.count+1)*(i+1), self.zzHeight-margin-(self.zzHeight-2*margin)/11*[y_itemArr[i] floatValue]/10);
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:startPoint];
[path addArcWithCenter:endPoint radius:1.5 startAngle:0 endAngle:2*M_PI clockwise:YES];
[path addLineToPoint:endPoint];
//繪制連線
CAShapeLayer *layer = [CAShapeLayer layer];
layer.path = path.CGPath;
layer.strokeColor = [UIColor redColor].CGColor;
layer.lineWidth = 1.0;
[self.layer addSublayer:layer];
//繪制點
CAShapeLayer *layer1 = [CAShapeLayer layer];
layer1.frame = CGRectMake(endPoint.x-2, endPoint.y-2, 4, 4);
layer1.backgroundColor = [UIColor blackColor].CGColor;
[self.layer addSublayer:layer1];
//繪制虛線
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
[shapeLayer setStrokeColor:[UIColor blackColor].CGColor];
[shapeLayer setLineWidth:1];
[shapeLayer setLineJoin:kCALineJoinRound];
//設置虛線的線寬及間距
[shapeLayer setLineDashPattern:[NSArray arrayWithObjects:[NSNumber numberWithInt:2], [NSNumber numberWithInt:3], nil]];
//創建虛線繪制路徑
CGMutablePathRef path = CGPathCreateMutable();
//設置y軸方向的虛線
CGPathMoveToPoint(path, NULL, point.x, point.y);
CGPathAddLineToPoint(path, NULL, point.x, self.zzHeight-margin);
//設置x軸方向的虛線
CGPathMoveToPoint(path, NULL, point.x, point.y);
CGPathAddLineToPoint(path, NULL, 1.3*margin, point.y);
//設置虛線繪制路徑
[shapeLayer setPath:path];
CGPathRelease(path);
[self.layer addSublayer:shapeLayer];
startPoint = endPoint;
}
//給x軸加標注
for (int i=0; i<x_itemArr.count; i++) {
CGFloat xLWidth = ((self.zzWidth-2*margin)/(x_itemArr.count+1)) <= 25 ? ((self.zzWidth-2*margin)/(x_itemArr.count+1)) : 25;
UILabel *lab = [[UILabel alloc] initWithFrame:CGRectMake(1.3*margin+(self.zzWidth-2*margin)/(x_itemArr.count+1)*(i+1)-xLWidth/2, self.zzHeight-margin, xLWidth, 20)];
lab.text = x_itemArr[i];
lab.textColor = [UIColor blackColor];
lab.adjustsFontSizeToFitWidth = YES;
lab.textAlignment = NSTextAlignmentCenter;
[self addSubview:lab];
}
效果圖如下:

扇形圖
扇形圖制作需要首先計算每一條數據占數據總和的百分比,然后以頁面中心點為中心,指定半徑,開始畫扇形,每條數據對應一個扇形,起點半徑每次都不一樣,知道最后一條數據畫完,可以正好得到一個整圓。
代碼如下:
CGPoint yPoint = CGPointMake(self.zzWidth/2, self.zzHeight/2);
CGFloat startAngle = 0;
CGFloat endAngle;
float r = self.zzHeight/3;
//求和
float sum=0;
for (NSString *str in y_itemArr) {
sum += [str floatValue];
}
for (int i=0; i<x_itemArr.count; i++) {
//求每一個的占比
float zhanbi = [y_itemArr[i] floatValue]/sum;
endAngle = startAngle + zhanbi*2*M_PI;
CAShapeLayer *layer = [CAShapeLayer layer];
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:yPoint radius:r startAngle:startAngle endAngle:endAngle clockwise:YES];
[path addLineToPoint:yPoint];
[path closePath];
CGFloat bLWidth = self.zzHeight/6+5 >= 45 ? 40 : self.zzHeight/6;
CGFloat size = self.zzHeight/6+5 >= 45 ? 9 : 5;
CGFloat lab_x = yPoint.x + (r + bLWidth/2) * cos((startAngle + (endAngle - startAngle)/2)) - bLWidth/2;
CGFloat lab_y = yPoint.y + (r + bLWidth*3/8) * sin((startAngle + (endAngle - startAngle)/2)) - bLWidth*3/8;
UILabel *lab = [[UILabel alloc] initWithFrame:CGRectMake(lab_x, lab_y, bLWidth, bLWidth*3/4)];
lab.text = [NSString stringWithFormat:@"%@\n%.2f%@",x_itemArr[i],zhanbi*100,@"%"];
lab.textColor = [UIColor blackColor];
lab.numberOfLines = 0;
lab.font = [UIFont boldSystemFontOfSize:size];
lab.textAlignment = NSTextAlignmentCenter;
[self addSubview:lab];
layer.path = path.CGPath;
layer.fillColor = zzRandomColor.CGColor;
layer.strokeColor = [UIColor clearColor].CGColor;
[self.layer addSublayer:layer];
startAngle = endAngle;
}
效果圖如下:

文件目錄截圖

尾聲
簡易的三種畫法,僅用於展示數據,封裝類和Demo已經上傳到了GitHub上,希望能給大家帶來幫助,也希望能看到大神的更精彩的分享。
小小數據統計(柱狀圖、折線圖、扇形圖)
注:本文著作權歸作者,由demo大師代發,拒絕轉載,轉載需要作者授權
