Charts: Melhorias de desempenho

Criado em 14 abr. 2015  ·  44Comentários  ·  Fonte: danielgindi/Charts

Existem planos para melhorar o desempenho da biblioteca da forma que Philip fez com MPAndroidCharts?
Com seus aprimoramentos, agora é possível renderizar milhares de pontos de dados sem problemas no Android.
Dei uma olhada rápida na implementação de gráficos ios e, pelo que vi, é baseada na implementação original de MPAndroidCharts sem os aprimoramentos de desempenho mais recentes.

Fazê-lo renderizar milhares de pontos também seria ENORME para a biblioteca, pois tornaria todas as versões comerciais inúteis (a maioria das quais é uma perda de tempo e dinheiro de qualquer maneira).

enhancement help wanted

Comentários muito úteis

Estou carregando mais de 13.000 registros em gráficos de linha para iOS. Porém, os gráficos congelam a IU durante o carregamento. Além disso, após o carregamento, se o usuário selecionar qualquer ponto, também demorará muito para realçar a seleção.

Todos 44 comentários

O gargalo de desempenho original na versão Android eram muitas alocações extras (de matrizes) dentro do código de renderização. A memória não deve ser alocada dentro do código de renderização. Portanto, @PhilJay moveu esse código para um Buffer que é pré-alocado e delegou os cálculos de renderização às classes Buffer durante a renderização.

Optei por não mover os cálculos de renderização para as classes Buffer, mas apenas pré-alocar a memória necessária da mesma maneira - mas ter os cálculos de renderização no mesmo loop do código de renderização. Dessa forma, é muito mais fácil gerenciar o código.

Além disso, é um ganho de desempenho que os cálculos de renderização não estejam sendo feitos dentro de funções extras e os dados sejam repetidos apenas uma vez dentro do código de renderização em vez de duas vezes.

A propósito, no Swift o desempenho é MUITO melhor do que o Java de qualquer maneira, então você teria visto esse ganho de desempenho mesmo sem pré-alocar esses arrays.

Para explicá-lo graficamente, isto é / estava sendo feito no código de renderização:

  • [COMEÇAR A REPRESENTAÇÃO]
  • Loop sobre DataSets
  • - Alocar matriz para pontos deste DataSet - Agora pré-alocado em ambas as plataformas
  • - Calcular pontos para renderização - _Movido para Buffers na versão Android_
  • - Renderize esses pontos
  • [COMMIT RENDERING]

Observe também que em Java, abstrações (funções, classes, herança) têm um ótimo preço. Não é à toa que o próprio Google escreveu uma recomendação importante :

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.

Resumindo:

  • Você pode se sentir confortável trabalhando com milhares de pontos de dados!
  • Estou tentando convencer Phil a mover os cálculos de pontos de volta para os loops de renderização para mantê-los mais simples de manter ;-)

Obrigado pelas suas explicações Daniel. Não tenho certeza do que tirar disso, no entanto.
O que fiz foi configurar o projeto mais básico (veja o código abaixo) e o desempenho não é comparável com a versão do Android, nem perto para ser completamente honesto. Usar mil pontos de dados resulta em enormes framedrops quando você chega perto de exibir a quantidade máxima de pontos de dados (diminua o zoom completamente), mesmo na maioria dos dispositivos iOS atuais, como iPad Mini3 e iPhone6. Como eu disse, o MPAndroidcharts pode renderizar vários milhares em dispositivos muito mais lentos sem suar muito.

substituir função 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;
}

Bem, eu não testei o desempenho de todos os gráficos ainda - então preciso fazer isso logo.
O gargalo é provavelmente uma alocação que perdi em algum lugar ... Vou testar e informá-lo! :-)

Muito obrigado Daniel. Ansioso para saber o que você pode extrair disso. Seria incrível ter um companheiro viável para MPAndroidCharts no iOS.

Bem, eu brinquei um pouco com o LineChartRenderer (que é particularmente lento em comparação com, por exemplo, o BarChartRenderer) e Instruments diz que drawPath do CGContext é o culpado aqui.
Tentei atenuar esse problema usando UIBezierPath, mas o desempenho é o mesmo assim que você chama stroke () no caminho. Antes disso, o desempenho do desenho é ótimo, mas o caminho é preenchido em relação ao ponto inicial e final, não o que queremos para um gráfico de linha simples.
Espero que você tenha um pouco mais de sorte para encontrar uma solução para isso.

Estou testando isso agora e, sim, parece que o CGContextStrokePath real sofre de baixo desempenho.
Um dos maiores rebatedores é a linha tracejada. Ao desativá-lo, o desempenho ~ dobra. Mas ainda é ruim com mil pontos.
Estou lendo alguns documentos da Apple para descobrir como tornar o CoreGraphics mais rápido

Sim, o Core Graphics definitivamente está tornando os caminhos lentos. Parece que acontece por causa da resolução - a resolução nos dispositivos Apple mais recentes são muito altas, o que significa mais pixels para renderizar.

Acho que o CG está renderizando na CPU em vez de na GPU. Talvez alguém conheça uma maneira de mudar isso?

CG está definitivamente usando a CPU para renderização e, pelo que eu sei, não há como mudar isso.
A renderização da GPU significaria usar OpenGL, infelizmente. Que pena que CG é tão lento em comparação com a forma como o Android renderiza essas coisas na CPU.

Na verdade, são as CPUs dos dispositivos que são lentas. Na maioria dos casos, um processo muito lento
A CPU oferece uma experiência muito melhor com iOS do que uma CPU rápida com Android.

Mas a Apple não pensou sobre os casos em que um sistema operacional ideal não é
suficiente para mantê-lo rápido.

Eu acho que quando usamos muitos pontos, podemos apenas evitar animações - mas
Ainda espero encontrar uma maneira de melhorar o desempenho da Linha
gráficos baseados.

Parece que especificamente o sistema de desenho de caminho é lento, e quando
brincar com Mitre e Flatness, e desativar linhas tracejadas e
Antialiasing - o desempenho fica muito melhor para 500-700 pontos em um
iPhone 6, mas ainda Jerky com 1000

Pode haver uma chance de usar o UIBezierPath. Como eu disse, essa coisa é suficientemente rápida assim que você não chama 'traço', o que essencialmente diz ao sistema que o caminho é um traço e não deve ser preenchido do ponto inicial ao ponto final. Não tenho ideia do que está acontecendo com isso no fundo, mas isso mostra que o desenho do gráfico em si não é o problema por si só.

No entanto, como não consegui encontrar uma maneira de usar o UIBezierPath corretamente para o gráfico de linha, pode ser uma candidatura viável para as linhas de grade, pois é possível enganar o caminho para desenhar sem chamar stroke. Mesmo que isso seja 'errado' do ponto de vista da API, deve produzir um melhor desempenho.

O UIBezierPath é apenas um invólucro UIKit em torno de CGPath, CGContextDrawPath,
etc.
A diferença de desempenho observada em alguns casos se deve ao fato de
configurando o CG primeiro, com as propriedades do UIBezierPath de
anti-serrilhamento, limite de mitra etc.

Na verdade, não há absolutamente nenhuma razão para usá-lo quando você sabe como usar
Core Graphics.

E sim, precisamos chamar "traço", pois queremos traçar esse caminho ...
não para preenchê-lo.
Na maioria dos casos, acariciar é mais difícil para o sistema do que preencher sólidos
cor, porque precisa cuidar da largura das linhas, das junções
entre as linhas e a forma das junções.

Na sexta-feira, 17 de abril de 2015 às 10:50, AlBirdie [email protected] escreveu:

Pode haver uma chance de usar o UIBezierPath. Como eu disse, aquela coisa
é suficientemente rápido assim que você não chama 'derrame', que essencialmente
diz ao sistema que o caminho é um traço e não deve ser preenchido a partir do
ponto de partida para o ponto de extremidade. Eu não tenho ideia do que está acontecendo com isso em
o fundo, mas isso mostra que o desenho do gráfico em si não é o
problema por si só.

No entanto, como não consegui encontrar uma maneira de usar o UIBezierPath corretamente para
o gráfico de linha, pode ser uma candidatura viável para as linhas de grade como um
poderia enganar o caminho para desenhar sem chamar o traço. Mesmo que seja
'errado' do ponto de vista da API, deve produzir um melhor desempenho.

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/danielgindi/ios-charts/issues/29#issuecomment -93937181
.

@danielgindi , você já pensou que se a animação está deixando as coisas mais lentas, que tal desenhar todas as linhas sem animação e usar uma visão de máscara cobrindo-as e, em seguida, animar a visão de máscara para imitar a animação?

Bem, essa é uma ótima ideia! :)

Embora haja uma desvantagem:
Isso prejudicará o tipo de animação que você pode fazer com ele. como nós permitimos
animar o eixo Y para que o gráfico "cresça" e a maneira como a linha se preenche
no eixo X também é diferente de quando há apenas um traço.

Minha lista de coisas para tentar é:

  1. De alguma forma, melhore CoreGraphics ou eleve parte da renderização para o
    GPU

    1. Pré-renderizar todos os quadros da animação - isso atrasará o início da animação e

      consome uma quantidade considerável de memória

    2. Sua ideia de mascaramento - que limita os tipos de animações

Se houver outras ideias, adoraria ouvi-las!

Daniel, você já tentou descarregar o trabalho para a GPU?
Estou muito, muito insatisfeito com a solução comercial com a qual estamos trabalhando atualmente (API terrível, totalmente fechada e muitos bugs que fazem o aplicativo travar) e tendo tanto sucesso com o MPAndroidCharts, adoraríamos mudar para Eventualmente, gráficos iOS se o desempenho estiver no mesmo nível. Fique tranquilo, seu trabalho será recompensado. ;)

Tentando algumas técnicas diferentes, farei uma atualização em alguns dias!

Na segunda-feira, 20 de abril de 2015 às 12h38, AlBirdie [email protected] escreveu:

Daniel, você já tentou descarregar o trabalho para a GPU?
Estou muito, muito insatisfeito com a solução comercial que estamos atualmente
trabalhando com (API terrível, totalmente fechada e muitos bugs que causam
o aplicativo travasse), e tendo tanto sucesso com MPAndroidCharts, nós
adoro mudar para gráficos iOS eventualmente se o desempenho estiver no mesmo nível. Descanso
com certeza, seu trabalho seria recompensado. ;)

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/danielgindi/ios-charts/issues/29#issuecomment -94408574
.

@AlBirdie que tipo de gargalo de desempenho você encontrou? Atualmente, possuo um produto que desenha gráficos como os gráficos ios, já tínhamos uma biblioteca de gráficos internamente. Também estou preocupado com o desempenho, atualmente, apenas carregamos 100-1000 conjuntos de dados, parece ok agora.

Também estou pensando em mudar para gráficos iOS, se possível, no futuro, mas nossa biblioteca tinha gestos que podem ter conflitos com gráficos iOS.

O problema de desempenho é uma taxa de quadros lenta nas animações quando precisa
desenhe 500-1000 linhas em um gráfico de linha.

Em relação aos Gestos - estamos usando UIGestureRecognizers padrão - que você
pode desativar, modificar ou trabalhar com. Tudo é padronizado. :-)

Na segunda-feira, 20 de abril de 2015 às 12h53, Xuan [email protected] escreveu:

@AlBirdie https://github.com/AlBirdie que tipo de apresentação
gargalo que você conheceu? Atualmente, possuo um produto que desenha gráficos apenas
como o ios-charts, já tínhamos uma biblioteca de gráficos internamente. Eu também me preocupo
sobre o desempenho, atualmente, carregamos apenas 100-1000 conjuntos de dados, parece ok
agora.

Também estou pensando em mudar para gráficos iOS, se possível, no futuro,
mas nossa biblioteca tinha gestos que poderiam entrar em conflito com gráficos ios.

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/danielgindi/ios-charts/issues/29#issuecomment -94411060
.

@danielgindi bem, acho que usamos a visualização de máscara para superar as animações ... Nosso gráfico de linha tem camada de gradiente. Como sua demonstração, sua animação pode fazer ambas as direções X + Y ao mesmo tempo, enquanto nós apenas fazemos a direção X. Não tenho certeza se o truque da máscara pode ajudá-lo.
O que tenho em mente agora é que se tivéssemos um vetor para descrever sua direção X + Y, talvez haja uma chance de usar o truque da máscara ... aguardamos os resultados!

@ liuxuan30 apenas desempenho lento geral, eu acho. As animações não são um problema, pois não estou trabalhando com elas. Estou trabalhando em gráficos financeiros onde você precisa ter vários conjuntos de dados em um único gráfico (várias ações + uma gama de indicadores). Para um intervalo de dados de 250 itens que facilmente somam vários milhares de pontos que precisam ser renderizados de uma vez durante a panorâmica e a compressão. A solução comercial com a qual estou trabalhando atualmente faz isso muito bem (usando OpenGL você pode renderizar milhares de pontos sem sobrecarregar a CPU), mas não sou amigo das bibliotecas de código fechado onde você tem que esperar meses para corrigir os bugs.
Eu me sentiria muito mais confortável com gráficos ios, especialmente porque a API de MPAndroidCharts é incrivelmente fácil de trabalhar.

Entendo, os dados financeiros são um desastre. Nosso servidor força apenas para enviar até 1000 conjuntos de dados para o dispositivo móvel, reduzindo assim nossa sobrecarga. Existe alguma chance de usar OpenGL para gráficos ios? @danielgindi

O suporte a OpenGL seria o melhor. Um gráfico de linha renderizado por GPU provavelmente seria suficiente por enquanto.
Infelizmente, não tenho absolutamente nenhuma ideia sobre OpenGL, caso contrário, ficaria feliz em ajudar.

Há uma melhoria com CGContextStrokeLineSegments em oposição ao uso de caminhos, então você deve tentar isso.
Ainda tentando outras maneiras de melhorar as coisas :-)

Obrigado Daniel, vou criar um pequeno aplicativo de teste que compara as duas versões uma contra a outra para ver o que é. Que ganhos de desempenho você obteve com o novo LineSegments?

@AlBirdie você sente a diferença com os segmentos de linha?

Também acabei de perceber: no android, para obter o desempenho máximo, você define a camada de hardware - nesse caso, as linhas tracejadas não são tracejadas, são todas sólidas.

Portanto, em primeiro lugar, se você desabilitar as linhas tracejadas no iOS, também terá um aumento significativo!

Mas acho que posso realmente desenhá-lo usando um OpenGL ES no CIImage, mas preciso ter muito cuidado porque se uma linha do GL for executada quando o aplicativo estiver inativo, ele irá travar.

Também há uma chance de que eu ainda possa permitir traços pré-renderizando uma textura. Vai dar um pouco de trabalho e não é minha prioridade principal, mas estou começando um projeto paralelo de uma camada OpenGL que pode substituir perfeitamente o CGContext.

Em vez de usar o OpenGL para desenhar, você também pode tentar reduzir para Core Animation. Talvez a classe CAShapeLayer pudesse funcionar. A Apple recomenda usar vários CAShapeLayer s ao renderizar um caminho complicado, portanto, pode ser necessário dividir o segmento de linha em vários segmentos. Usar o Core Animation deve mover o trabalho para a GPU.

Por anos, em meu trabalho diário, usamos um produto comercial que, conforme observado acima, por @AlBirdie faz uso extensivo de OpenGL e, portanto, ignora o CoreGraphics para tudo, exceto anotações. Certamente eles parecem ser capazes de lidar com conjuntos de dados muito grandes com renderização bastante suave e afirmam usar a GPU para isso. No entanto, sua abordagem vem com enormes dores de cabeça, não menos bugs que eles aparentemente não podem se incomodar em consertar, como chamadas de renderização assíncrona que travam no OpenGL quando o aplicativo fica em segundo plano, estruturas de classe idiotas e restrições insanas de customização. O que eu quero não existe hoje, mas nos gráficos iOS vejo que pode ser o caminho para chegar lá. De qualquer forma, para mim, a confiabilidade sempre vence o desempenho, mas é por uma margem mínima, ambas são extremamente importantes.

ps na minha opinião as linhas tracejadas são um resquício dos dias em que os computadores não tinham a opção de renderizar em cores ou mesmo em tons de cinza - elas não são necessárias, a menos que estejamos renderizando em preto e branco puro e fazendo algo que parece antigo livro-texto impresso em tipografia, certo? ;) Portanto, é muito menos importante otimizar para aqueles do que para o caso geral de 10 mil pontos.

Absolutamente com você @onlyforart em relação às linhas tracejadas.
Dada a sua descrição sobre sua biblioteca comercial de gráficos, estou me perguntando se temos usado o mesmo produto. :) Finalmente nos livramos disso. O que levei quase três meses para implementar (mesmo que não fosse longo o suficiente para contornar bugs e restrições graves (por exemplo, mira), levou apenas duas semanas com iOSCharts ('estruturas de classe idiotas';)). Total perda de tempo e dinheiro.

@AlBirdie sim, é esse mesmo. Nem mencione a mira. Feito com a ajuda de demasiada Newcastle Brown Ale e, sem dúvida, voltado para o mercado corporativo (onde um API nodoso é na verdade um fator de vendas positivo, pois prende os clientes a um caro ciclo de suporte / manutenção). Você conhecia a história desses caras? na verdade (em seu passado profundo), eles foram verdadeiros pioneiros na indústria de software. De qualquer forma, é hora de seguir em frente e olhar para o futuro agora.
Na maioria das vezes, desenhamos gráficos Candlestick (são aplicativos do setor financeiro). O que eu realmente quero para iOS e Android é algo que seja realmente muito fácil com HighCharts / HighStock no mundo HTML5 / Javascript:

  1. grande número de pontos de dados (10K ou mais)
  2. consolidação automática de dados OHLC em barras escalonadas sensíveis (por exemplo, mostrar barras de 1h quando o fator de zoom for apropriado, ou barras de 1m ou 1s quando diminuir o zoom)
  3. panorâmica e rolagem suaves
  4. belisque para ampliar
  5. sobreposição de várias séries de dados e anotações e retículos, alguns programaticamente e alguns pela interação do usuário, por exemplo, para definir um preço limite, tudo renderizado sem problemas
  6. (aqui está o kicker - HighStock não ajuda com isso! embora pareça bastante óbvio para mim) busca incremental de dados (com lookahead), por exemplo, buscar dados de baixa resolução para todo o conjunto de dados e, como com aplicativos de mapas, buscar o hi-rez dados (por exemplo, dados de "tick" de milissegundos) apenas para a área visualizada do gráfico
    Não estamos usando iOS-Charts ainda, embora esteja na minha lista de "tarefas" e chegando mais perto do topo, então eu não olhei muito dentro do código ainda, mas assim que eu fiz - provavelmente no próximo mês - Vou investigar tudo isso.
    Voltando à renderização, a tendência do OpenGL de travar se as circunstâncias não forem perfeitas é uma preocupação. O GLKit pode ajudar no desenho da GPU; Eu também havia me perguntado se o SpriteKit poderia ajudar (a renderização do gráfico não está a um milhão de milhas de fazer jogos), mas agora o GLKit parece um candidato melhor.

LOL @onlyforart , você me teve na Newcastle Brown Ale. : +1: :)
Estou no mesmo barco em relação aos seus requisitos (trabalhando em produtos financeiros também), mas sim, vamos voltar ao desenho real desses gráficos. Ansioso por suas descobertas no futuro.

@onlyforart , @AlBirdie obrigado por seus insights :-)

É muito bom ver pessoas trocando produtos comerciais pela nossa biblioteca, embora eu me sinta mal por elas ... Estou em conflito!

Eu estava hesitante em deixar o OpenGL ter uma parte disso porque eu sabia que havia possíveis travamentos se não fosse gerenciado perfeitamente, e isso não é realmente possível em um aplicativo UIKit. Se você está usando OpenGL para criar um jogo, tudo é uma tela OpenGL e você não precisa se preocupar com uma chamada UIKit tentando causar uma renderização OpenGL enquanto está em segundo plano.

@onlyforart seu ponto sobre linhas tracejadas está correto, mas infelizmente eu tive experiência com clientes que exigem linhas tracejadas. Houve um caso no Android em que, para aumentar o desempenho, o desenvolvedor teve que mudar a camada para uma camada de hardware e disse ao cliente que as linhas tracejadas se tornariam linhas sólidas, esse é o custo. E, claro, há uma opção para mover todo o código de desenho para OpenGL, mas desenhar uma única linha é uma dor de cabeça, mas você pode criar uma textura para uma linha tracejada e trabalhar com ela. Eles não queriam pagar por isso, então as linhas tracejadas certamente não eram tão críticas, mas eles fizeram muito barulho sobre isso.

Uma nota para mim mesmo: tente usar o GLKit para a renderização. Veja o que acontece.

E se eu pegar sua lista:

  1. _ "um grande número de pontos de dados (10K ou mais)" _ - estamos trabalhando nisso :) Não posso dizer sobre o Android, pois movê-lo para o GL será um PITA ainda maior, mas já está tendo um desempenho muito bom por alavancando a camada de hardware, que faz tudo com base na GPU.
  2. _ "consolidação automática de dados OHLC em barras escalonadas sensíveis" _ - colocaremos os filtros de aproximação em uso muito em breve, então acho que isso resolverá isso. Em vez de ter muitas barras de 1m que você não consegue ler, você terá uma barra aproximada de 1 hora, etc.
  3. _ "panorâmica e rolagem suaves" _ - feito :-)
  4. _ "belisque para ampliar" _ - concluído :-)
  5. _ "sobreposição de várias séries de dados e anotações e retículos" _ - Não sei se entendi corretamente, mas atualmente existe o gráfico Combinado que pode sobrepor vários tipos de gráfico, e cada tipo de gráfico pode aceitar vários conjuntos de dados. Além disso, você sempre pode conectar em ViewPortHandler e obter coordenadas para que possa sobrepor o que quiser no topo do char
  6. busca incremental de dados - estamos planejando abstrair a fonte de dados, embora ainda tenhamos as APIs antigas para definir conjuntos de dados estáticos (será apenas uma fonte de dados embutida que funciona com eles). Acho que isso também atenderá às suas necessidades, mas não sabemos quando chegaremos lá ainda

@danielgindi , não se sinta mal por eles. Se o produto que você está desenvolvendo é basicamente um tomate podre e ainda assim você cobra muito caro por ele, as pessoas acabarão mudando para um produto diferente. Não há nada de errado nisso. Venho desenvolvendo gráficos financeiros há vários anos, usei quase todas as soluções para iOS que existem atualmente e, na verdade, escrevi meu próprio mecanismo de gráficos em ActionScript3 nos últimos dias, então me sinto bastante confiante em dizer isso iOSCharts e MPAndroidCharts são, na verdade, os únicos produtos que posso recomendar a qualquer desenvolvedor que precise de gráficos em seu aplicativo. Todo o resto lá fora simplesmente não serve.

Em relação ao segundo requisito, se vocês vão implementar isso, tem que ser opcional. Temos esse tipo de consolidação em um de nossos produtos de gráficos e, em vez disso, os clientes estão mudando constantemente para uma frequência fixa. Alterar as frequências durante o zoom acabou sendo não apenas confuso para o usuário médio de gráficos financeiros, mas também os usuários avançados ficavam incomodados porque queriam frequências fixas.

Nunca imaginamos forçar isso aos usuários! Você pode ver que o código já inclui os Filtros, e em MPAndroidCharts você pode ver que historicamente os filtros foram habilitados por uma propriedade que define o filtro (qualquer filtro personalizado ou integrado), mas removidos posteriormente devido a mudanças estruturais.

Quando o implementarmos, a funcionalidade permanecerá a mesma - será apenas mais um recurso interessante :-)

@AlBirdie Re "Com relação ao segundo requisito, se vocês vão implementar isso, tem que ser opcional. Temos esse tipo de consolidação em um de nossos produtos de gráficos e os clientes estão constantemente mudando para uma frequência fixa. Mudando as frequências durante o zoom não eram apenas confusas para o usuário médio de gráficos financeiros, mas também os usuários avançados ficavam incomodados porque queriam frequências fixas. " Concordo totalmente - isso é para gráficos para usuários informativos / não comerciais. Os usuários comerciais têm necessidades diferentes.

@danielgindi Re "abstraindo a fonte de dados" talvez seja algo com o qual possamos contribuir, se tivermos tempo. Sem promessas, mas vou adicioná-lo ao nosso backlog.

Alguém brincou com a divisão do código de desenho em segmentos separados (CALayer.drawsAsynchronously)? Isso pode ajudar no caso de permitir desenhar extras de gráfico, cada conjunto de dados, a grade e os eixos separadamente. Dada a minha humilde experiência com CoreGraphics (leia; absolutamente nenhuma ;-)), não fiz nenhum experimento com isso, só encontrei quando estava procurando o GLKit e como ele poderia melhorar o desempenho do gráfico.

Eu precisava mostrar um gráfico de bastão de vela com 10k pontos de dados, então executei algumas medições de tempo em CandleStickChartRenderer.drawDataSet ().

Descobriu-se que a maior parte do tempo é gasta na chamada de dataSet.entryIndex (linhas 76,77).

Posso estar enganado, mas parece que a chamada dataSet.entryIndex () é redundante, pois os valores _minX, _maxX são sempre iguais ao minx, maxx retornado de dataSet.entryIndex ()

Eu consegui fazer um gráfico de bastão de vela com 10k pontos de dados panorâmico / zoom suavemente. mudando
CandleStickChartRenderer.swift, linha 76,77 de:

var minx = max (dataSet.entryIndex (entry: entryFrom, isEqual: true), 0);
var maxx = min (dataSet.entryIndex (entry: entryTo, isEqual: true) + 1, entries.count);

para

var minx = max (_minX, 0);
var maxx = _maxX + 1;

Fiz a mesma alteração em LineChartRenderer e consegui mostrar um gráfico de bastão de vela / linha combinado com 2 séries de dados (10k pontos de dados cada)

Uau, isso é um grande aumento de desempenho @dorsoft !

Acabei de testar isso e não pude acreditar no que via. Mesmo em um iPad 2 com 4 CombinedCharts exibindo até três conjuntos de dados cada um com 250 pontos de dados cada e cálculos automáticos mín. / Máx. Do eixo y, agora somos capazes de aplicar panorâmica e zoom em todos os gráficos simultaneamente de uma maneira bastante suave. Não é 60fps, mas perto. Impressionante para um dispositivo tão antigo e MUITO (!) Mais rápido do que a solução OpenGL comercial da qual falamos anteriormente.

Acho que tenho que tentar isso :) E preciso discutir com Phil também para
entenda se há alguma implicação ...

Acabei de ler isso, parece muito interessante, mas vai precisar de alguns testes intensos para ver se é realmente adequado para todos os cenários :-)

Eu criei um PR com aprimoramento de desempenho do gráfico de velas.
O aprimoramento foi testado exaustivamente usando valores mín. / Máx. E nulos da escala automática.

Encontrei um possível gargalo. Em um gráfico em tempo real Adicionando muitas entradas por segundo ao gráfico, percebi que automaticamente o calcMinMax do conjunto de dados é chamado logo após CADA values.append(e)

A função calcMinMax determina os valores mínimo e máximo usando .forEach que está fazendo com que a CPU gaste mais de 60% no loop dos valores, além do thread principal.

Estou realizando algum experimento desativando o cálculo mínimo / máximo ou usando loop for nativo em vez de array .forEach

@danielgindi por favor dê uma olhada, é realmente calcMinMax em todos os valores necessários? Eu calculo os valores min / max Y manualmente em meu código e apenas em valores visíveis , então talvez você possa expor algum booleano para habilitar / desabilitar o cálculo automático min / max e melhorar o desempenho removendo a função forEach e evitar chamadas de função.

```
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 Por favor, faça isso em um tíquete separado e vou priorizá-lo.

@jjatie Obrigado, basta abrir # 3166

Estou carregando mais de 13.000 registros em gráficos de linha para iOS. Porém, os gráficos congelam a IU durante o carregamento. Além disso, após o carregamento, se o usuário selecionar qualquer ponto, também demorará muito para realçar a seleção.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

anhltse03448 picture anhltse03448  ·  3Comentários

newbiebie picture newbiebie  ·  3Comentários

Bharati555 picture Bharati555  ·  4Comentários

JW00332 picture JW00332  ·  4Comentários

Shunshine07 picture Shunshine07  ·  3Comentários