Es fällt mir schwer, Charts von Version 2 (Swift 2.3) auf 3 (Swift 3) zu migrieren.
Grundsätzlich kann ich die x-Beschriftungen (Daten) nicht richtig mit den entsprechenden Plots ausrichten.
Das hatte ich vorher in Version 2:
https://i.stack.imgur.com/wOL3t.png
In Version 2 hatte ich Werte für die Tage 7, 8, 10 und 11. Es fehlte also ein Tag in der Mitte, aber die Beschriftungen waren korrekt mit den Plots ausgerichtet.
Und das habe ich in Version 3:
https://i.stack.imgur.com/arIL2.png
In Version 3 wurden die "Labels" in der x-Achse jetzt durch double ersetzt (bei Datumsangaben ist es seit 1970 ein timeInterval) und über einen Formatierer formatiert. Der Graph ist also unbestreitbar "korrekter", da das Diagramm den Wert für den 9. richtig extrapoliert, aber ich kann nicht finden, wie man die Beschriftungen unter den entsprechenden Diagrammen platziert.
Dies ist mein Code für die x-Achse:
```
let chartView = LineChartView()
...
let xAxis = chartView.xAxis
xAxis.labelPosition = .bottom
xAxis.labelCount = entries.count
xAxis.drawLabelsEnabled = true
xAxis.drawLimitLinesBehindDataEnabled = true
xAxis.avoidFirstLastClippingEnabled = true
// Datumsformatierer für x-Werte einstellen
let xValuesNumberFormatter = ChartXAxisFormatter()
xValuesNumberFormatter.dateFormatter = dayNumberAndShortNameFormatter // zB "wed 26"
xAxis.valueFormatter = xValuesNumberFormatter
Here is the ChartXAxisFormatter class I created:
Stiftung importieren
Diagramme importieren
Klasse ChartXAxisFormatter: NSObject {
var dateFormatter: DateFormatter?
}
Erweiterung ChartXAxisFormatter: IAxisValueFormatter {
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
if let dateFormatter = dateFormatter {
let date = Date(timeIntervalSince1970: value)
return dateFormatter.string(from: date)
}
return ""
}
}
```
Die Werte hier sind also korrekt, die Formatierung ist korrekt, die Form des Diagramms ist korrekt, aber die Ausrichtung der Beschriftungen mit den entsprechenden Diagrammen ist nicht gut.
Danke für Ihre Hilfe
Ich habe das gleiche Problem zuvor mit Zeitstempeln ausgeführt und es wird dadurch verursacht, dass auf der x-Achse ein interpolierter Zeitstempel gerendert wird. Dies bedeutet im Grunde, dass die Zeitstempel, die zu den Labels führen, die einen dateFormatter verwenden, _nicht die Zeitstempel für Ihre Ergebnisse sind_, was dazu führt, dass die Labels nicht übereinstimmen.
Angenommen, Sie haben x-Werte [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]. Der x-Achsen-Renderer druckt möglicherweise 2.5 tatsächlich als Beschriftung, um die Beschriftungen gleichmäßig auf der x-Achse zu verteilen, obwohl dieser bestimmte x-Wert in Ihrem Dataset _nicht_ ist. Wenn Sie dann davon ausgehen, dass Sie Zeitstempel verwenden, bedeutet dies, dass der dateFormatter möglicherweise einen dazwischenliegenden Zeitstempel als Datum formatiert. Wenn Sie nach Tag formatieren, führt dies dazu, dass Ihre Labels nicht mit Ihren Scores übereinstimmen, obwohl das Label korrekt ist (da Sie es grundsätzlich nach Tag abrunden). Wenn Sie nach _Tag Stunde:Minute_ formatieren, sehen Sie, dass das Label tatsächlich ein interpoliertes Datum ist.
Ich habe das Problem auf meiner Seite gelöst, indem ich auf Array-Indizes zurückgegriffen habe, anstatt Zeitstempel für die x-Achse zu verwenden und einen benutzerdefinierten X-Achsen-Formatierer zu verwenden:
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)
}
}
Vielen Dank für Ihre Antwort!
Und die sehr klare Erklärung, dass die Zeitstempel interpoliert werden, macht wirklich Sinn.
Ich werde deine Lösung ausprobieren und dir Bescheid geben.
Vielen Dank!
@4np Ich denke, dass Sie dann Ihr Array von ChartDataEntry auch mit xValues als Indizes anstelle von Zeitintervallen definieren müssen, oder?
Wie so:
// 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, das hat funktioniert! Mein Diagramm ist jetzt das gleiche wie in Version 2.
Aber ich musste meiner xAxis noch 2 weitere Dinge hinzufügen:
// 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
Danke für Ihre Hilfe.
Außerdem habe ich dort ein Problem bei StackOverflow eröffnet:
http://stackoverflow.com/questions/41720445/ios-charts-3-0-align-x-labels-dates-with-plots
Wenn Sie einen SO-Account haben und Ihre Antwort dort kopieren / einfügen möchten, nehme ich Ihre Antwort auch dort gerne entgegen.
Vielen Dank
Fred
Außerdem habe ich dieses Problem offen gelassen, bis die Charts-Entwickler die Möglichkeit haben, es sich anzusehen und vielleicht eine Möglichkeit vorzustellen, wie die Beschriftungen ausgerichtet werden sollen.
Denn ich muss mich jetzt zwischen 2 schlechten Lösungen entscheiden:
Bitte teilen Sie uns Ihre Meinung mit.
@frederic-adda
Ich habe es geschafft das Problem zu lösen
XAxis.granularity = 1.0 muss ein Tag sein. das ist das wichtigste
Das kleinste Datum muss 0 sein
(TimeInSeconds - miniDate) / (3600.0 * 24.0)
Und der Trick liegt im Formatierer
Wir machen den umgekehrten Vorgang, um das Datum abzurufen
Sei date2 = Date (timeIntervalSence1970: (Wert * 3600 * 24) + miniTime)
Rückgabe dateFormatter.string (von: date2)
vergessen Sie nicht
DateFormatter.timeZone = NSTimeZone (Abkürzung: "GMT + 0:00") als TimeZone!
Die Demo ist macOS
Der Link ist https://github.com/thierryH91200/Charts-log
Registerkarte Zeilendatum
@thierryH91200 Danke Thierry!
Ich werde versuchen, Ihre Lösung sofort umzusetzen.
Es funktionierte! Fantastisch!
Danke für Ihre Hilfe!
Cool @thierryH91200 , das scheint tatsächlich der richtige Weg zu sein 👍
Das funktioniert bei mir nicht
@frederic-adda hast du die Lösung für dein Problem gefunden??
Tatsächlich habe ich ein Problem beim Anzeigen von Daten auf der X-Achse. Ich zeige Datumsangaben auf der X-Achse an, indem ich den X-Wert von ChartDataEntry als TimeInterval festlege, aber dann zeigt das Diagramm die Daten nicht richtig an. Beim Festlegen des X-Werts von ChartDataEntry als Array-Index werden die Daten angezeigt.
Hier ist mein Code zum Festlegen des X-Werts von ChartDataEntry als TimeInterval
for (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]];
}
Hat jemand versucht, die oben genannten Lösungen bei Verwendung mehrerer LineChartDataSets in einem Diagramm zum Laufen zu bringen, konnte sie erfolgreich zum Laufen gebracht werden?
Ich habe Probleme, eine Lösung zu finden, wenn sich ein Dataset im Vergleich zum anderen in der Größe unterscheiden kann.
dh
let x = LineChartDataSet(values: values1, label: "test 1") // count 5
let y = LineChartDataSet(values: values2, label: "test 2") // count 8
Hilfreichster Kommentar
Ich habe das gleiche Problem zuvor mit Zeitstempeln ausgeführt und es wird dadurch verursacht, dass auf der x-Achse ein interpolierter Zeitstempel gerendert wird. Dies bedeutet im Grunde, dass die Zeitstempel, die zu den Labels führen, die einen dateFormatter verwenden, _nicht die Zeitstempel für Ihre Ergebnisse sind_, was dazu führt, dass die Labels nicht übereinstimmen.
Angenommen, Sie haben x-Werte [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]. Der x-Achsen-Renderer druckt möglicherweise 2.5 tatsächlich als Beschriftung, um die Beschriftungen gleichmäßig auf der x-Achse zu verteilen, obwohl dieser bestimmte x-Wert in Ihrem Dataset _nicht_ ist. Wenn Sie dann davon ausgehen, dass Sie Zeitstempel verwenden, bedeutet dies, dass der dateFormatter möglicherweise einen dazwischenliegenden Zeitstempel als Datum formatiert. Wenn Sie nach Tag formatieren, führt dies dazu, dass Ihre Labels nicht mit Ihren Scores übereinstimmen, obwohl das Label korrekt ist (da Sie es grundsätzlich nach Tag abrunden). Wenn Sie nach _Tag Stunde:Minute_ formatieren, sehen Sie, dass das Label tatsächlich ein interpoliertes Datum ist.
Ich habe das Problem auf meiner Seite gelöst, indem ich auf Array-Indizes zurückgegriffen habe, anstatt Zeitstempel für die x-Achse zu verwenden und einen benutzerdefinierten X-Achsen-Formatierer zu verwenden: