是否有计划以Philip使用MPAndroidCharts的方式来提高库的性能?
通过他的增强,现在可以在Android上流畅地渲染数千个数据点。
我快速浏览了ios-charts实现,并从中看到它基于原始的MPAndroidCharts实现,而没有最新的性能增强。
使其具有成千上万的点数,对于库来说也是巨大的,因为它将有效地使所有商业版本变得毫无用处(无论如何,其中大多数都是浪费时间和金钱的)。
Android版本中最初的性能瓶颈是渲染代码中有许多额外的(数组)分配。 不应在渲染代码中@ PhilJay已将该代码移动到预先分配的Buffer中,并在渲染时将渲染计算委托给Buffer类。
我选择不将渲染计算移至Buffer类,而只是以相同的方式预分配所需的内存-但将渲染计算与渲染代码置于同一循环中。 这样,管理代码要容易得多。
另外,在额外的函数中不进行渲染计算也可以提高性能,并且数据在渲染代码中仅循环一次,而不是两次。
顺便说一句,在Swift性能方面,FAR还是比Java更好,因此,即使不预先分配这些数组,您也会看到性能提高。
为了以图形方式对其进行解释,这是/正在渲染代码中执行的操作:
还要注意,在Java中,抽象(函数,类,继承)的价格很高。 Google自己写了一个重要的建议并非没有:
Be careful with code abstractions
Often, developers use abstractions simply as a "good programming practice,"
because abstractions can improve code flexibility and maintenance.
However, abstractions come at a significant cost:
generally they require a fair amount more code that needs to be executed,
requiring more time and more RAM for that code to be mapped into memory.
So if your abstractions aren't supplying a significant benefit, you should avoid them.
总结一下:
感谢您的解释,丹尼尔。 不过,我不太确定该怎么做。
我所做的是设置了最基本的项目(请参见下面的代码),并且其性能无法与Android版本相提并论,甚至说实话也是如此。 一旦您接近显示最大数量的数据点(完全缩小),即使在大多数最新的iOS设备(如iPad Mini3和iPhone6)上,使用一千个数据点都会导致大量帧丢失。 正如我所说,MPAndroidcharts可以在速度较慢的设备上渲染数千个字符,而不会费力。
覆盖func viewDidLoad(){
super.viewDidLoad()
lineChart = LineChartView(frame: view.frame);
view.addSubview(lineChart);
lineChart.backgroundColor = UIColor.whiteColor()
lineChart.descriptionText = "Just a test"
lineChart.leftAxis.enabled = false
lineChart.legend.enabled = false
setData(20)
}
func setData(range:Float) {
var count = 1000;
var xVals = Array<String>();
for(var i = 0; i<count; i++) {
xVals.append(String(i) + "");
}
var yVals = Array<ChartDataEntry>();
for (var i = 0; i<count; i++) {
var mult = range + 1
var val:Float = Float(random()) * mult + 3;
yVals.append(ChartDataEntry(value: val, xIndex: i));
}
var lineSet:LineChartDataSet = LineChartDataSet(yVals: yVals, label: " ");
lineSet.drawCirclesEnabled = false;
lineSet.drawValuesEnabled = false;
var lineData:LineChartData = LineChartData(xVals: xVals, dataSet: lineSet);
lineChart.data = lineData;
}
我还没有测试所有图表的性能-所以我需要尽快进行测试。
瓶颈可能是我在某处错过的分配...我会测试一下,让您知道! :-)
非常感谢Daniel。 期待您可以从中得到什么。 在iOS上拥有MPAndroidCharts的可行伴侣真是太好了。
好吧,我在LineChartRenderer上玩了一点(与BarChartRenderer相比,它特别慢),Instruments说CGContext的drawPath是罪魁祸首。
我尝试通过改用UIBezierPath来缓解此问题,但是在路径上调用stroke()后,性能是相同的。 在此之前,绘图性能很好,但是路径充满了起点和终点,而不是我们想要的简单折线图。
希望您能找到更多解决方案的运气。
我现在正在对此进行测试,是的,似乎实际的CGContextStrokePath
表现不佳。
虚线是主要的击球手之一。 禁用它时,性能会翻倍。 但是它仍然很穷,只有一千分。
我正在阅读Apple文档,以了解如何使CoreGraphics更快
是的,Core Graphics确实在缓慢地渲染路径。 这似乎是由于分辨率而发生的-新型Apple设备上的分辨率非常高,这意味着需要渲染更多像素。
我认为CG是在CPU而不是在GPU上渲染的。 也许有人知道改变这种状况的方法?
CG绝对是使用CPU进行渲染,据我所知,没有办法对此进行更改。
不幸的是,GPU渲染将意味着使用OpenGL。 糟糕的是,与Android在CPU上渲染这些东西相比,CG是如此之慢。
实际上是设备的CPU变慢了。 在大多数情况下,速度非常慢
与使用Android的快速CPU相比,CPU在iOS上提供的体验要好得多。
但是苹果公司没有考虑过没有最佳操作系统的情况。
足以保持快速。
我猜想当我们使用很多点时,我们只能避免使用动画-但是
我仍然希望找到一种提高Line性能的方法
基于图表。
似乎特别是路径绘制系统很慢,
玩“斜接和平整度”,并禁用虚线和
抗锯齿-在500-700点的分辨率下,性能会好得多
iPhone 6,但仍然生涩,只有1000
使用UIBezierPath可能会有机会。 正如我所说,只要您不调用“笔画”,该操作就足够快了,这实际上告诉系统该路径是笔画,不应从起点到终点进行填充。 我不知道背景是怎么回事,但这表明图形绘制本身并不是问题。
但是,由于我找不到合适的折线图使用UIBezierPath的方法,因此对于网格线来说这可能是一个可行的选择,因为它可以欺骗绘制路径而不会产生笔触。 即使从API的角度来看这是“错误的”,也应该会产生更好的性能。
UIBezierPath只是围绕CGPath,CGContextDrawPath,
等等。
在某些情况下观察到的性能差异是由于
首先使用的UIBezierPath属性设置CG
抗锯齿,斜接限制等
实际上,当您知道如何使用它时,绝对没有理由使用它
核心图形。
是的,我们确实需要调用“中风”,因为我们确实想要中风该路径...
不填补它。
在大多数情况下,抚摸对系统来说比填充固体更难
颜色,因为它需要照顾线条的宽度,所以连接
线和连接的形状之间。
2015年4月17日,星期五,上午10:50,AlBirdie [email protected]写道:
使用UIBezierPath可能会有机会。 就像我说的那样
只要不打“中风”就足够快
告诉系统路径是笔划,不应从路径中填充
端点的起点。 我不知道这是怎么回事
背景,但这表明图形绘制本身不是
本身发行。但是,由于我找不到正确使用UIBezierPath的方法
折线图,对于网格线来说,这可能是一个可行的备选方案
可以在不打笔的情况下欺骗绘制路径。 即使那是
从API的角度来看“错误”,它应该会产生更好的性能。-
直接回复此电子邮件或在GitHub上查看
https://github.com/danielgindi/ios-charts/issues/29#issuecomment -93937181
。
@danielgindi您是否考虑过,如果动画使速度变慢,如何绘制没有动画的所有线条,并使用覆盖它的遮罩视图,然后对遮罩视图进行动画处理以模仿动画?
好吧,这是个好主意! :)
尽管有一个缺点:
它将削弱您可以使用的动画类型。 在我们允许的情况下
为Y轴设置动画,以使图表“增长”,以及线条填充的方式
在X轴上的位置也与只有笔触时的位置不同。
我的尝试清单是:
- 以某种方式增强CoreGraphics或将部分渲染提升到
显卡
- 预渲染所有动画帧-它将延迟动画开始,并且
消耗大量内存- 您的遮罩创意-限制了动画种类
如果还有其他想法,我很想听听他们的意见!
丹尼尔(Daniel),您是否尝试过将工作转移到GPU?
我真的非常不满意我们目前正在使用的商业解决方案(糟糕的API,严重关闭的状态以及导致应用崩溃的大量错误),并且在MPAndroidCharts上取得了如此巨大的成功,我们希望切换到如果性能不相上下,iOS最终将成为图表。 放心,您的工作将得到回报。 ;)
尝试几种不同的技术,我将在几天之内为您提供更新!
2015年4月20日,星期一,下午12:38,AlBirdie [email protected]写道:
丹尼尔(Daniel),您是否尝试过将工作转移到GPU?
我真的非常不满意我们目前的商业解决方案
使用(糟糕的API,严重关闭,以及大量导致错误的错误,
该应用程序崩溃),并且在MPAndroidCharts上取得了如此巨大的成功,
如果性能可以与之媲美,我最终会切换到iOS图表。 休息
放心,您的工作将得到回报。 ;)-
直接回复此电子邮件或在GitHub上查看
https://github.com/danielgindi/ios-charts/issues/29#issuecomment -94408574
。
@AlBirdie您遇到了什么样的性能瓶颈? 我目前拥有一种像ios-charts一样绘制图表的产品,我们已经在内部拥有一个图表库。 我还担心性能,目前,我们只加载100-1000个数据集,现在看来还可以。
我还考虑在将来可能的情况下更改为ios-charts,但是我们的库中的手势可能与ios-charts冲突。
性能麻烦在于,当必须执行以下操作时,动画的帧速率会变慢
在折线图中绘制500-1000条线。
关于手势-我们正在使用标准的UIGestureRecognizers-
可以禁用,修改或使用。 一切都标准化了。 :-)
2015年4月20日,星期一,下午12:53,Xuan [email protected]写道:
@AlBirdie https://github.com/AlBirdie什么样的表现
你遇到瓶颈了吗? 我目前拥有一款仅能绘制图表的产品
像ios-charts一样,我们内部已经有一个图表库。 我也很担心
关于性能,目前,我们只加载100-1000个数据集,似乎还可以
现在。我还考虑在将来可能的情况下更改为ios-chart,
但是我们的库中的手势可能会与ios图表产生冲突。-
直接回复此电子邮件或在GitHub上查看
https://github.com/danielgindi/ios-charts/issues/29#issuecomment -94411060
。
@danielgindi好吧,我认为我们可以使用遮罩视图来克服动画效果...我们的折线图具有渐变层。 作为演示,您的动画可以同时执行X + Y方向,而我们只需执行X方向。 我不确定这把面具能不能帮到您。
我现在的想法是,如果我们有一个向量来描述您的X + Y方向,也许有机会使用遮罩把戏……期待您的结果!
我猜@ liuxuan30只是一般的性能下降。 动画不是问题,因为我不使用动画。 我正在研究财务图表,您需要在一个图表中包含多个数据集(多只股票+一系列指标)。 对于250个项目的数据范围,可以轻松地将多达数千个点加在一起,而在平移和收缩过程中需要一次渲染这些点。 我目前正在使用的商业解决方案可以很好地做到这一点(使用OpenGL,您可以渲染数千个点而不会导致CPU过载),但是我不是封闭源代码库的好朋友,在该库中,您必须等待几个月才能修复错误。
我对ios-charts感到更自在,尤其是因为MPAndroidCharts的API非常易于使用。
我知道,财务数据是灾难。 我们的服务器强制仅将多达1000个数据集发送到移动设备,因此减少了我们的过载。 有机会将OpenGL用于ios图表吗? @danielgindi
OpenGL支持将是王牌。 GPU渲染的折线图可能现在就足够了。
不幸的是,我对OpenGL完全一无所知,否则我很乐意提供帮助。
与使用路径相比,CGContextStrokeLineSegments有一个改进,因此您应该尝试一下。
仍在尝试其他改进方法:-)
谢谢Daniel,我将创建一个小型测试应用程序,将两个版本相互比较,以了解是什么。 使用新的LineSegments后,您获得了哪些性能提升?
@AlBirdie您觉得线段与众不同吗?
我也刚刚意识到:在android中,为了获得最佳性能,请将其设置为硬件层-在这种情况下,虚线不是虚线,它们都是固定的。
因此,首先,如果您在iOS上禁用了虚线,那么您的使用也会得到显着提高!
但是我想我可以在CIImage上使用OpenGL ES来绘制它,但是需要非常小心,因为如果在应用程序处于非活动状态时运行了一条GL行,它将崩溃。
另外,我仍然可以通过预渲染纹理来允许破折号。 这将需要一些工作,这不是我的主要任务,但是我正在开始一个OpenGL层的辅助项目,该项目可以无缝替换CGContext。
除了使用OpenGL进行绘制外,您还可以尝试将其降低到“核心动画”。 也许CAShapeLayer类可以工作。 Apple建议在渲染复杂路径时使用多个CAShapeLayer
s,因此您可能需要将线段分成多个段。 使用Core Animation应该将工作移至GPU。
多年来,在我的日常工作中,我们一直使用@AlBirdie上面提到的商业产品来广泛使用OpenGL,从而绕过CoreGraphics处理注释以外的所有内容。 当然,他们似乎能够以相当平滑的渲染处理相当大的数据集,并且他们声称为此使用了GPU。 然而,他们的方法带来了巨大的麻烦,尤其是它们似乎无法被解决的错误,例如异步渲染调用在应用程序进入后台时在OpenGL中崩溃,愚蠢的类结构以及对可自定义性的疯狂限制。 我想要的东西今天不存在,但是在iOS图表中,我看到这可能是到达那里的方式。 无论如何,对我而言,可靠性每次都会胜过性能,但这是微不足道的,两者都很重要。
我认为ps是计算机无法选择以彩色或什至灰度渲染的日子的宿醉-除非我们将其渲染为纯黑白并制作看起来像旧的东西,否则不需要它们凸版印刷的教科书,当然可以吗? ;)因此,针对那些优化进行优化远不如针对一般的10K点情况进行优化重要。
绝对与您@onlyforart有关虚线。
鉴于您对您的商业图表库的描述,我想知道我们是否一直在使用相同的产品。 :)我们终于顺便抛弃了它。 我花了三个月的大部分时间来实施(即使那还不足以解决严重的错误和限制(例如,十字准线),而使用iOSCharts仅仅花了两个星期的时间(“愚蠢的类结构”;)。 浪费时间和金钱。
@AlBirdie是的。 甚至不提十字准线。 借助过多的Newcastle Brown Ale制成,并且毫无疑问地瞄准了企业市场(粗糙的API实际上是一个积极的销售因素,因为它使客户陷入了昂贵的支持/维护周期)。 你知道那些家伙的历史吗? 实际上(在很久以前)他们是软件行业的真正先驱。 无论如何,现在该继续前进,展望未来。
我们主要绘制烛台图(这些是金融行业应用程序)。 对于iOS和Android,我真正想要的是使用HTML5 / Javascript世界中的HighCharts / HighStock实际上非常容易的事情:
大声笑@onlyforart ,你在纽卡斯尔·布朗·艾尔大学有我。 :+1::)
关于您的要求,我是同一人(也从事金融产品),但是,是的,让我们回到这些图表的实际图形上。 期待您将来的发现。
@onlyforart , @AlBirdie感谢您的见解:-)
看到人们为我们的图书馆放弃商业企业产品真是太好了,尽管我为他们感到难过……我很矛盾!
我很犹豫让OpenGL占有一席之地,因为我知道如果管理不当可能会导致崩溃,而在UIKit应用程序中这实际上是不可能的。 如果您使用OpenGL来创建游戏,则整个过程都是OpenGL画布,而不必担心UIKit调用会在后台导致OpenGL渲染的问题。
@onlyforart您关于虚线的观点是正确的,但不幸的是,我曾与要求使用虚线的客户有经验。 在Android上存在一种情况,要提高性能,开发人员必须将层更改为硬件层,并告诉客户虚线将变为实线,这就是成本。 当然,可以选择将所有绘图代码都移至OpenGL,但是随后绘制一条直线是一件令人头疼的事,但是您可以为虚线创建纹理并使用它。 他们不想为此付出代价,所以虚线当然不是那么关键,但是确实引起了很大的反响。
给自己的注释:尝试使用GLKit进行渲染。 走着瞧吧。
如果我接受您的清单:
@danielgindi ,不要为他们感到
关于第二个要求,如果你们要实现这一点,它必须是可选的。 我们在其中一种图表产品中进行了这种合并,而客户正在稳步转向固定频率。 事实证明,在缩放过程中更改频率不仅会使普通的财务图表用户感到困惑,而且使高级用户感到烦恼,因为他们想要固定的频率。
我们从来没有想过将其强加给用户! 您可以看到代码已经包含过滤器,并且在MPAndroidCharts中可以看到,过滤器历史上是由设置过滤器(任何自定义过滤器或内置过滤器)的属性启用的,但由于结构更改后来被删除了。
当我们实现它时,功能将保持不变-这将是另一个很酷的功能:-)
@AlBirdie Re“关于第二个要求,如果你们要实现这一点,它必须是可选的。我们在其中的一种图表产品中已经进行了这种合并,而客户正在稳步向固定频率过渡。更改事实证明,缩放期间的频率不仅使普通的财务图表用户感到困惑,而且使高级用户感到恼火,因为他们想要固定的频率。” 完全同意-这是供信息/非交易用户使用的图表。 交易用户有不同的需求。
@danielgindi关于“抽象数据源”,如果有时间的话,这可能是我们可以做的事情。 没有承诺,但我将其添加到我们的积压中。
是否有人玩过将绘图代码拆分为单独的线程(CALayer.drawsAsynchronously)? 如果这允许绘制额外的图表,每个数据集,网格和轴,则可能会有所帮助。 鉴于我对CoreGraphics的非常不起眼的经验(阅读;一无所获;-)),我还没有进行任何实验,只是在寻找GLKit以及如何改善图表性能时才发现它。
我需要显示一个包含10k数据点的烛台图,因此我在CandleStickChartRenderer.drawDataSet()上进行了一些时间测量。
事实证明,大部分时间都花在了调用dataSet.entryIndex(第76,77行)上。
我可能会弄错,但data_setup.entryIndex()调用似乎是多余的,因为_minX,_maxX值始终等于从dataSet.entryIndex()返回的minx,maxx
我已经成功制作了一个烛光图表,其中包含了10k个数据点的平移/缩放。 通过改变
CandleStickChartRenderer.swift,第76,77行来自:
var minx = max(dataSet.entryIndex(entry:entryFrom,isEqual:true),0);
var maxx = min(dataSet.entryIndex(entry:entryTo,isEqual:true)+ 1,entry.count);
至
var minx = max(_minX,0);
var maxx = _maxX + 1;
我对LineChartRenderer进行了相同的更改,并能够显示带有2个数据系列的组合烛台/折线图(每个数据点10k数据点)
哇, @dorsoft可以大大提高
我已经测试过了,我简直不敢相信自己的眼睛。 即使在具有4个组合图的iPad 2上最多显示三个数据集(每个数据集各有250个数据点)和y轴的自动最小/最大计算,我们现在也能够以相当平滑的方式同时平移和缩放所有图表。 它不是60fps,而是接近。 这种旧设备和WAY(!)的速度比我们之前讨论的商用OpenGL解决方案快,给人留下深刻的印象。
我想我必须尝试一下:)并且还需要与Phil讨论以
了解是否有任何影响...
我刚刚读了这篇,看起来很有趣,但是需要进行一些严格的测试才能确定它是否真正适用于所有场景:-)
我创建了具有蜡烛图性能增强功能的PR。
使用自动定标的最小/最大和零值对增强进行了彻底测试。
我发现了可能的瓶颈。 在一个实时图表中,每秒向图表中添加许多条目,我注意到在每个EACH values.append(e)
之后,都会自动调用数据集的calcMinMax。
calcMinMax函数使用.forEach确定最小值和最大值,这导致CPU在循环使用这些值时花费了60%以上,而且在主线程中。
我正在执行一些实验来禁用最小/最大计算或使用本机for循环而不是array .forEach
@danielgindi请看一下,真的需要所有值calcMinMax吗? 我在代码中手动计算了最小/最大Y值,并且仅对可见值进行了计算,因此也许您可以暴露一些布尔值以启用/禁用最小/最大自动计算,并提高性能,删除forEach函数并避免函数调用。
```
open override func calcMinMax()
{
guard !values.isEmpty else { return }
_yMax = -Double.greatestFiniteMagnitude
_yMin = Double.greatestFiniteMagnitude
_xMax = -Double.greatestFiniteMagnitude
_xMin = Double.greatestFiniteMagnitude
values.forEach { calcMinMax(entry: $0) }
}
```
@samueleperricone请将此票单独
@jjatie谢谢,刚打开#3166
我正在为iOS的折线图中加载13000多个记录。 但是,图表会在加载时冻结UI。 同样,在加载后,如果用户选择了任何一点,则也需要花费太多时间来突出显示该选择。
最有用的评论
我正在为iOS的折线图中加载13000多个记录。 但是,图表会在加载时冻结UI。 同样,在加载后,如果用户选择了任何一点,则也需要花费太多时间来突出显示该选择。