Charts: Pare a duplicação de rótulos de eixo.

Criado em 24 ago. 2015  ·  51Comentários  ·  Fonte: danielgindi/Charts

Dentro do aplicativo, tenho um problema em que os rótulos no eixo esquerdo de BarChartView ou LineChartView se repetem.

Primeiro adicionei o snippet abaixo para garantir que o número de rótulos no eixo não exceda o valor máximo nos dados y.

self.chartView.leftAxis.labelCount = self.chartView.data.yMax > YAxisMaxLabelCount ? YAxisMaxLabelCount : self.chartView.data.yMax;

Isso garantiu que, se o valor máximo nos dados y fosse 3 , haveria apenas rótulos 3 dentro do eixo. Agora, isso funcionou bem se o gráfico não fosse interativo, ou seja, o usuário não pudesse ampliar o gráfico.

Assim que o usuário amplia, obviamente, a contagem dos rótulos permanece a mesma e o formatador de valor preenche as lacunas, permitindo que um valor se repita.

_Exemplo de eixo sem valores duplicados_
screen shot 2015-08-24 at 5 07 29 pm

_Exemplo do mesmo gráfico, mas ampliado_
screen shot 2015-08-24 at 5 07 54 pm

As capturas de tela mostram o eixo esquerdo repetindo o valor 2 . Qual é a sua melhor sugestão para resolver esse problema de rótulos repetidos? Qualquer ajuda seria bem vinda. Se precisar de mais alguma informação me avise.

Obrigado

Comentários muito úteis

Isso é lançado em 2.2.4, como o recurso granularity

Todos 51 comentários

Eu acho que não é o rótulo duplicado, mas contém valores decimais e um formatador inteiro? Você precisa verificar qual é o valor bruto para cada rótulo do eixo x e como você o formata quando desenha os rótulos do eixo x no renderizador do eixo y.

Consegui fazer isso adicionando uma verificação para garantir que o intervalo de cada rótulo seja sempre um valor inteiro.
A mudança está dentro da função computeAxisValues() $ da classe ChartYAxisRenderer

var interval = ChartUtils.roundToNextSignificant(number: Double(rawInterval))
if(_yAxis.valueFormatter?.maximumFractionDigits == 0)
{
    interval = interval < 1 ? 1 : floor(interval)
}

Se o formatador de valor solicitar que não haja dígitos fracionários, ele diminuirá os intervalos e, se for menor que o número inteiro 1 , ele definirá o intervalo para 1 .

Gostaria de um pull request?

Obrigado pela ajuda.

Se você está tendo valores decimais, por que maximumFractionDigits é 0? Acho que é o problema do formatador.

Eu não quero valores decimais, é por isso que defino maximumFractionDigits = 0

amigo, seus dados são decimais, e você só quer usar formatador para abandonar os dígitos da fração, não faz sentido. Por que não converter seus dados em números inteiros primeiro?

Os valores de y que dou ao gráfico são

(1, 3, 2, 0, 0, 7, 0)

Depois de criar um ChartDataSet esses valores são duplicados.

ChartDataSet, label: , 7 entries:
ChartDataEntry, xIndex: 0, value 1.0
ChartDataEntry, xIndex: 1, value 3.0
ChartDataEntry, xIndex: 2, value 2.0
ChartDataEntry, xIndex: 3, value 0.0
ChartDataEntry, xIndex: 4, value 0.0
ChartDataEntry, xIndex: 5, value 7.0
ChartDataEntry, xIndex: 6, value 0.0

Isso ocorre porque sua classe ChartDataEntry mantém o valor como Double

/// the actual value (y axis)
public var value = Double(0.0)

Embora os valores tenham sido alterados para o dobro, os gráficos mostram o incremento correto de rótulos no início, mas assim que o gráfico é ampliado, o ChartYAxisRenderer deseja preencher as lacunas e como meu formatador de valor removeu qualquer dígitos fracionários ele mostra como um valor duplicado.

Não quero que o gráfico assuma que quero valores adicionais entre os números inteiros, pois só quero mostrar um rótulo para um número inteiro.

Isso me leva a ver que estou fornecendo os dados corretos ao gráfico, mas o gráfico está fazendo suposições sobre o que quero fazer. Isso é bom para um padrão, mas deve fornecer a opção de mostrar apenas números inteiros no eixo também.

Ao adicionar a verificação em relação ao formatador de valor, ele permite esse comportamento. Você pode conhecer uma maneira melhor de fornecer esse comportamento em vez de verificar o formatador de valor, mas é um caso de uso que algumas pessoas desejam.

Acabei de notar que estou usando a base de código no commit a7e30dd16fbfaecb8e44c01ad8618a3a745fd101 e quando essa alteração é implementada no último commit de Charts, ela não age conforme o esperado.

Você seria capaz de aconselhar a melhor forma de alcançar o comportamento que eu quero?

Anexei um gif do comportamento esperado.

Abaixo, você pode ver que nenhum rótulo mostra o mesmo valor e o gráfico não está tentando colocar nenhum rótulo entre outros rótulos, pois há o requisito de que os rótulos sejam valores inteiros.

chart

Ah entendi. Se você ampliar para, digamos, [3,4], o intervalo seria [3,4] e o eixo deseja exibir [3,0, 3,2, 3,4, 3,6, 3,8, 4,0], e você não deseja dígitos fracionários, é isso?

Na verdade, não há nada que eu possa fazer... já que seus dados são muito pequenos e temos que exibir de 4 a 6 rótulos lá... E se o intervalo for [0,1], e você precisar exibir 5 rótulos, o que pode você exibe outros dígitos fracionários?

Acho que não há problema em exibir dígitos fracionários se o intervalo for muito pequeno, mas se você realmente não quiser, poderá fazê-lo como fez. Ou você aceitaria mostrar apenas o rótulo máximo e mínimo chamado showOnlyMinMaxEnabled

BTW, suas capturas de tela funcionam muito bem, resolveu seu problema

Há também algumas propriedades para ajudá-lo a limitar a contagem de rótulos. Você pode tentar modificar e ajustar para diferentes níveis de escala.

    public func setLabelCount(count: Int, force: Bool)
    {
        _labelCount = count

        if (_labelCount > 25)
        {
            _labelCount = 25
        }
        if (_labelCount < 2)
        {
            _labelCount = 2
        }

        forceLabelsEnabled = force
    }

Para ter o mesmo comportamento no eixo Y é necessário definir um limite de zoom Y. #382

388

@steprescott , #388 resolveu seu problema?

Observando o commit do problema #388, a única alteração é uma nova propriedade na janela de visualização.

Como eu obteria o comportamento pretendido que é mostrado no gif, mas com suas alterações?

Oi @steprescott , tente com [_chartView.viewPortHandler setMaximumScaleY: 2.f]; por exemplo, assim a granularidade do zoom não é tão grande para mostrar valores repetidos. Um bom exemplo é quando você tem uma linha de caractere horizontal sem limite, todos os valores de Y são repetidos quando o zoom é grande. Com MaximumScaleY essa repetição não acontece.

Sem limite:
screen shot 2015-09-22 at 23 29 16

Com limite 2f:
screen shot 2015-09-22 at 23 30 07

Oi @noais

Isso funciona em um conjunto de dados que tem um intervalo maior de valores, mas se você tiver um intervalo pequeno de valores, por exemplo, sendo uma matriz de valores de 0 a 7, aumentar o zoom por um fator de 2 poderia fornecer rótulos duplicados.

Embora limitar o fator de zoom tenha resolvido seu problema, ele não resolve o problema de repetir valores inteiros.

Eu obtive meus resultados esperados ao editar a classe ChartYAxisRenderer apontando para commit a7e30dd16fbfaecb8e44c01ad8618a3a745fd101.

Isso foi feito reduzindo o valor.

var interval = ChartUtils.roundToNextSignificant(number: Double(rawInterval))
if(_yAxis.valueFormatter?.maximumFractionDigits == 0)
{
    interval = interval < 1 ? 1 : floor(interval)
}

Embora isso tenha funcionado (mas não ao usar o HEAD deste repositório), sinto que vocês conhecerão um lugar melhor dentro de sua estrutura para colocar isso para fornecer o mesmo resultado mostrado no gif.

Talvez uma propriedade allowRepeatingValues BOOL em um eixo. Vocês vão saber melhor.

Sim, você está certo, este foi um trabalho em torno. Deixe-me tentar ver se é fácil criar algum método como allowRepeatingValues.

Isso seria muito útil, obrigado.

Olá @noais e @liuxuan30. Você já teve a oportunidade de investigar isso? Consegui obter o efeito necessário usando a estrutura, mas não sei onde melhor essa propriedade deve ficar na estrutura e se há uma maneira melhor de obter o mesmo resultado.

Obrigado pelo seu tempo.

Ainda estou pensando que é porque o formatador que produziu rótulos duplicados com dígitos pequenos, não o algoritmo. Se você excluir o formatador, ele exibirá o número corretamente, certo?
Você pode resolvê-lo com seu código, mas não tenho certeza se é bom para todos.
@danielgindi o que você acha

Oi pessoal, votando em allowRepeatingValues, tenho números pequenos e não quero exibir o valor do eixo y duplicado

Quando todos os meus valores são zero, recebo esses rótulos de eixo repetidos -
chart

Além disso, notei que, embora o trecho de código que tenho faça o que preciso, ele não está removendo valores duplicados simplesmente permitindo apenas números inteiros. Portanto, verificar o formatador de número não é uma maneira horrível de adicionar isso.

O que esse snippet não permite é a remoção de valores duplicados, portanto, se os valores fossem 1.1, 1.2, 1.2, 1.3 e você desejasse manter o único dígito decimal, não funcionaria. Vocês saberão o melhor lugar e implementação para este recurso e para as pessoas gastarem tempo olhando para os problemas atuais do framework e para eles votarem isso mostra que é uma opção que outros também querem.

allowRepeatingValues ​​:+1:

@noais @liuxuan30 Você tem uma solução melhor para isso do que eu sugeri?

não, exceto para allowRepeatingValues ​​.. Porque seu problema original é sobre os formatadores. você não quer dígitos decimais em um nível, mas seus dados na verdade têm o próximo nível

Idealmente, o gráfico não deve mostrar valores repetidos, nunca! Os valores repetidos podem ser ocultados com alguma lógica, resultando em apenas valores únicos?

@vigyanhoon não está 'repetindo' valores por trás, é o formatador que faz com que o valor seja 'repetido'. Se não quiser repetir, dê um formatador decimal que possa resolver.

@liuxuan30 Você pode explicar o que quer dizer com "_dar um formatador decimal_"? Com meus dados dei um formatador que definiu o maximumFractionDigits = 0 . Não tenho certeza de como obter os resultados esperados com o que existe atualmente? Você conseguiu produzir um gráfico com o framework que dá os mesmos resultados do meu gif que postei no dia 28 de agosto?

Você pretendia usar numberFormatter.allowsFloats = NO, se sim, não me ajudou, ainda vejo INTs duplicados?! A única maneira que consegui NÃO exibir valores repetitivos é usar 2 rótulos no xAxis (superior/inferior)

@steprescott desculpe se não fui claro. MaximumFractionDigits não deve ser 0, caso contrário mostrará apenas a parte inteira. Eu encontrei problemas semelhantes, se o intervalo de dados for pequeno e 5 ~ 6 rótulos necessários, dando maximumFractionDigits = 0 terá valores repetidos. Não há nenhuma maneira fácil de corrigir isso, eu acho. pense se o intervalo de dados é [0,2], e eu tenho que exibir 5 rótulos: 0, 0.4,0.8,1.2,1.6, 2.0. Se aplicarmos maximumFractionDigits = 0, talvez 0, 0, 1, 1, 2, 2

@injectios , que tal MaximumFractionDigits = 2 ou até 4?

Ei a todos!
Estou com este mesmo problema.

@liuxuan30 dependendo do tipo de dados, não faz sentido ter decimais. Como um gráfico de humanos, você nunca terá 1,5 humanos, é 1 ou 2.

@jpros você conseguiu um ponto, mas do ponto de vista matemático, não podemos ter 4 rótulos sem decimais no intervalo [0,2].

Portanto, ative yAxis.showOnlyMinMaxEnabled para evitar valores repetidos como solução alternativa por enquanto,
Ou você implementa sua lógica para calcular seus próprios valores em ChartYAxisRenderer.computeAxis para evitar,
Ou temos que esperar pelo recurso 'allowRepeatValues'

@PhilJay , temos alguma solução para isso atualmente? :-)

De um POV Android (e ofc iOS), esta linha aqui: https://github.com/PhilJay/MPAndroidChart/blob/master/MPChartLib/src/com/github/mikephil/charting/renderer/YAxisRenderer.java#L108

Poderia ser um local para resolver este problema. Os float interval dos rótulos dos eixos foram calculados e podem ser usados ​​para evitar mais alterações nos rótulos se dois rótulos forem formatados igualmente.
Isso é apenas o que me vem à mente quando penso rapidamente sobre isso. O que você acha?

Eu me livrei da duplicação definindo um valor máximo

leftAxis.customAxisMax = maxYLabelCount

@vigyanhoon é uma coisa totalmente diferente, os valores podem ser milhões, enquanto maxYLabelCount não. customAxisMax é definir o valor máximo que o intervalo do eixo pode ser.

+1 para resolver o problema de renderização. Eu também tenho um gráfico de pessoas e estou tendo [0, 0, 1, 1, 2, 2]. Definir o numberFormatter.maximumFractionDigits para qualquer coisa diferente de 0 não faz sentido.

O código a seguir sugerido por @steprescott também foi corrigido para mim. Eu adicionei no meu fork aqui:

https://github.com/natanrolnik/ios-charts/commit/01df4d9264e0adbef4db88763075376f4a0f255c

Um PR seria capaz de fechar esta questão? O que você acha @danielgindi @liuxuan30 @steprescott ? Existem casos que este código não corrige? Se sim, quais são as melhores soluções?

@natanrolnik e se o usuário aumentar o zoom e o alcance se tornar [25.2, 25.3]? O intervalo seria 1,0 enquanto deveria ser, digamos 0,02.
Deve ajudar se o usuário definir especificamente o número da fração máxima como 0, limitamos o intervalo. Eu não testei valores negativos embora.
Ainda não temos uma solução melhor, mas acho que um recurso como 'allowRepeatValues' é o que podemos pensar?

Concordo em relação allowRepeatedValues !

Acho que o @steprescott é uma boa solução. Só precisa ajustar o valor um para uma variável de granularidade.

Com esse problema do @liuxuan30 não existe mais.

Se colocarmos este código na linha 75 do ChartYAxisRenderer:

interval = interval < granuality ? granuality : interval       

https://github.com/noais/ios-charts/compare/master...Noais
O que você acha?

Ok, isso agora está fechado, mas não está mesclado no mestre. Quando isso provavelmente aconteceria?

Isso é lançado em 2.2.4, como o recurso granularity

Não tenho certeza se devo postar esse problema aqui, mas faz sentido para mim.

Eu tenho um problema muito semelhante com meus rótulos xAxis. Eu tenho um IAxisValueFormatter personalizado que retorna strings por hora, dá horas como "22:00", "23:00" para alguns gráficos, dias da semana como este "Mon.", "Thu". para outros etc.

Quando o gráfico é ampliado demais, os valores começam a duplicar como mostrado aqui:

Screenshot 2019-07-19 at 17 59 11

Neste caso o recurso granularity não funciona pois funciona com a diferença entre números.

Você tem alguma idéia de como eu poderia impedir que esses rótulos se repetissem?

Obrigado

Definir granularidadeEnabled para trabalho falso para mim
leftAxis.granularityEnabled = true

Olá pessoal, eu quero fazer com que o valor xAxis não se repita ao aumentar o zoom
meu Formatador:
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
let date = Date(timeIntervalSince1970: valor)
return date.formattedString(withDateFormat: .daymonth)
}
também uso granularidade, mas ainda tenho o mesmo problema
xEixo.granularidade = 1,0
xAxis.granularityEnabled = true

alguem sabe como resolver pf?

@Aaimek
Estou com o mesmo problema, você encontrou a solução?

Eu tenho o mesmo problema quando forço a contagem de rótulos do eixo x e ploto alguns pontos.

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

Questões relacionadas

sjdevlin picture sjdevlin  ·  3Comentários

Aungbandlab picture Aungbandlab  ·  4Comentários

brytnvmg picture brytnvmg  ·  4Comentários

valeIT picture valeIT  ·  3Comentários

BrandonShega picture BrandonShega  ·  4Comentários