大數據(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上,地址:https://github.com/fuzheng0301/DrawChart,感謝star,希望能給大家帶來幫助,也希望能看到大神的更精彩的分享。