Estou tendo dificuldade para migrar Gráficos da versão 2 (Swift 2.3) para 3 (Swift 3).
Basicamente, não posso ter os rótulos x (datas) alinhados corretamente com os gráficos correspondentes.
Isso é o que eu tinha antes na versão 2:
https://i.stack.imgur.com/wOL3t.png
Na versão 2, eu tinha valores para os dias 7, 8, 10 e 11. Então estava faltando um dia no meio, mas os rótulos estavam corretamente alinhados com os gráficos.
E aqui está o que tenho na versão 3:
https://i.stack.imgur.com/arIL2.png
Na versão 3, os "rótulos" no eixo x agora foram substituídos por double (para datas, é um timeInterval desde 1970) e formatados por meio de um formatador. Então, indiscutivelmente, o gráfico está mais "correto" agora, já que o gráfico extrapola corretamente o valor para o 9º, mas não consigo descobrir como colocar os rótulos nos gráficos correspondentes.
Este é o meu código para o eixo x:
`` `
let chartView = LineChartView ()
...
deixe xAxis = chartView.xAxis
xAxis.labelPosition = .bottom
xAxis.labelCount = entries.count
xAxis.drawLabelsEnabled = true
xAxis.drawLimitLinesBehindDataEnabled = true
xAxis.avoidFirstLastClippingEnabled = true
// Defina o formatador de data dos valores x
let xValuesNumberFormatter = ChartXAxisFormatter ()
xValuesNumberFormatter.dateFormatter = dayNumberAndShortNameFormatter // por exemplo, "wed 26"
xAxis.valueFormatter = xValuesNumberFormatter
Here is the ChartXAxisFormatter class I created:
import Foundation
importar gráficos
classe ChartXAxisFormatter: NSObject {
var dateFormatter: DateFormatter?
}
extensão ChartXAxisFormatter: IAxisValueFormatter {
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
if let dateFormatter = dateFormatter {
let date = Date(timeIntervalSince1970: value)
return dateFormatter.string(from: date)
}
return ""
}
}
`` `
Então, os valores aqui estão corretos, a formatação está correta, o formato do gráfico está correto, mas o alinhamento dos rótulos com os gráficos correspondentes não é bom.
Obrigado pela ajuda
Corri o mesmo problema usando carimbos de data / hora antes e isso é causado pelo que está sendo renderizado no eixo x é um carimbo de data / hora interpolado. Isso basicamente significa que os carimbos de data / hora resultantes nos rótulos que usam um dateFormatter _não são os carimbos de data / hora para suas pontuações_, fazendo com que os rótulos não correspondam.
Por exemplo, vamos supor que você tenha valores x [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]. O renderizador do eixo x pode, na verdade, imprimir 2,5 como um rótulo tentando distribuir uniformemente os rótulos no eixo x, mesmo que esse valor x específico _não_ esteja em seu conjunto de dados. Se você considerar que está usando carimbos de data / hora, isso significa que dateFormatter pode formatar algum carimbo de data / hora intermediário como uma data. Conforme você formata por dia, isso resulta em seus rótulos não corresponderem às suas pontuações, embora o rótulo esteja correto (já que você basicamente o arredonda por dia). Se você formatar por _dia hora: minuto_ , verá que o rótulo é de fato uma data interpolada.
Resolvi o problema recorrendo ao uso de índices de matriz em vez de usar carimbos de data / hora para o eixo x e usando um formatador de eixo x personalizado:
import Foundation
import Charts
class MyCustomBottomAxisFormatter: NSObject, IAxisValueFormatter {
private var scores: [MyScoreObject]?
lazy private var dateFormatter: DateFormatter = {
// set up date formatter using locale
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale.current
dateFormatter.dateStyle = .short
dateFormatter.timeStyle = .none
return dateFormatter
}()
convenience init(usingScores scores: [MyScoreObject]) {
self.init()
self.scores = scores
}
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
let index = Int(value)
guard let scores = scores, index < scores.count, let date = scores[index].date else {
return "?"
}
return dateFormatter.string(from: date)
}
}
Muito obrigado pela sua resposta!
E a explicação muito clara sobre os carimbos de data / hora sendo interpolados, realmente faz sentido.
Vou tentar sua solução e informá-lo.
Obrigado!
@ 4np Eu acho que você tem que definir seu array de ChartDataEntry com xValues como índices também, em vez de intervalos de tempo, certo?
Igual a :
// Define chart yValues
var entries = [ChartDataEntry]()
for (index, score) in scores.enumerated() {
let yValue = score.value
let entry = ChartDataEntry(x: Double(index), y: yValue)
entries.append(entry)
}
@ 4np OK, funcionou! Meu gráfico agora é o mesmo da versão 2.
Mas, eu tive que adicionar mais 2 coisas ao meu xAxis:
// Show the limit lines behind each plot
xAxis.drawLimitLinesBehindDataEnabled = true
// Make sure that only 1 x-label per index is shown
xAxis.granularityEnabled = true
xAxis.granularity = 1
Obrigado pela ajuda.
Além disso, abri um problema no StackOverflow lá:
http://stackoverflow.com/questions/41720445/ios-charts-3-0-align-x-labels-dates-with-plots
Se você tem uma conta SO e deseja copiar / colar sua resposta lá, ficarei feliz em aceitar sua resposta lá também.
Obrigado
Fred
Além disso, deixei esse problema em aberto até que os desenvolvedores de gráficos tenham a chance de examiná-lo e talvez apresentem uma maneira de escolher como os rótulos devem ser alinhados.
Porque agora tenho que escolher entre 2 soluções ruins:
Por favor deixe nos saber o que você pensa.
@ frederic-adda
Consegui resolver o problema
XAxis.granularity = 1.0 deve ser um dia. isso é o mais importante
A menor data deve ser 0
(TimeInSeconds - miniDate) / (3600,0 * 24,0)
E todo o truque está no formatador
Fazemos a operação oposta para recuperar a data
Let date2 = Date (timeIntervalSince1970: (value * 3600 * 24) + miniTime)
Retornar dateFormatter.string (de: data2)
não esqueça
DateFormatter.timeZone = NSTimeZone (abreviação: "GMT + 0: 00") como TimeZone!
A demonstração é macOS
O link é https://github.com/thierryH91200/Charts-log
Guia Line Date
@ thierryH91200 Obrigado Thierry!
Vou tentar implementar sua solução imediatamente.
Funcionou! Fantástico!
Obrigado pela ajuda!
Legal @ thierryH91200 , parece mesmo o caminho a seguir 👍
Isso não funciona para mim
@frederic-adda encontrou a solução para o seu problema ??
na verdade, tenho problemas ao mostrar datas no X-Axis. Estou mostrando datas no eixo X definindo o valor X de ChartDataEntry como TimeInterval, mas o gráfico não mostra os dados corretamente. Ao definir o valor X de ChartDataEntry como índice de matriz, mostra os dados.
Aqui está meu código para definir o valor X de ChartDataEntry como TimeInterval
para (int i = 0; i <self.temperatureUpdates.count; i ++)
{
SFTemperatureUpdate * temperatureUpdate = [self.temperatureUpdates obje ctAtIndex: i ];
double yVal = [temperatureUpdate.value floatValue];
NSTimeInterval timeInterval = [temperatureUpdate.careatedAt timeIntervalSince1970];
double xVal = timeInterval;
[yVals1 addObject: [[ChartDataEntry alloc] initWithX: xVal y: yVal]];
}
Tentando fazer as soluções acima funcionarem ao usar vários LineChartDataSets em um gráfico, alguém conseguiu fazê-lo funcionar com sucesso?
Estou tendo problemas para encontrar uma solução quando um conjunto de dados pode ser diferente em tamanho em comparação com o outro.
ie
let x = LineChartDataSet(values: values1, label: "test 1") // count 5
let y = LineChartDataSet(values: values2, label: "test 2") // count 8
Comentários muito úteis
Corri o mesmo problema usando carimbos de data / hora antes e isso é causado pelo que está sendo renderizado no eixo x é um carimbo de data / hora interpolado. Isso basicamente significa que os carimbos de data / hora resultantes nos rótulos que usam um dateFormatter _não são os carimbos de data / hora para suas pontuações_, fazendo com que os rótulos não correspondam.
Por exemplo, vamos supor que você tenha valores x [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]. O renderizador do eixo x pode, na verdade, imprimir 2,5 como um rótulo tentando distribuir uniformemente os rótulos no eixo x, mesmo que esse valor x específico _não_ esteja em seu conjunto de dados. Se você considerar que está usando carimbos de data / hora, isso significa que dateFormatter pode formatar algum carimbo de data / hora intermediário como uma data. Conforme você formata por dia, isso resulta em seus rótulos não corresponderem às suas pontuações, embora o rótulo esteja correto (já que você basicamente o arredonda por dia). Se você formatar por _dia hora: minuto_ , verá que o rótulo é de fato uma data interpolada.
Resolvi o problema recorrendo ao uso de índices de matriz em vez de usar carimbos de data / hora para o eixo x e usando um formatador de eixo x personalizado: