I am working with library. Anybody know if is it possible to force show min and max label on x-axis.
What I have:
What I want to achieve:
My implementation:
private func prepareXAxis() {
lineChart.xAxis.labelPosition = .bottom
lineChart.xAxis.valueFormatter = ChartXAxisDateValueFormatter()
lineChart.xAxis.labelFont = UIFont.pmd_robotoRegular(ofSize: 13.0)
lineChart.xAxis.labelTextColor = UIColor.pmd_darkGrey
}
And implementation of my own ValueFormatter:
import Foundation
import Charts
class ChartXAxisDateValueFormatter: NSObject, IAxisValueFormatter {
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "hh:mm\ndd MMM"
return dateFormatter.string(from: Date(timeIntervalSince1970: value))
}
}
Edit
I added this code but first and last label on x-axis is still skipped:
lineChart.xAxis.axisMinimum = lineDataSet.xMin
lineChart.xAxis.axisMaximum = lineDataSet.xMax
lineChart.xAxis.avoidFirstLastClippingEnabled = false
lineChart.xAxis.granularity = 1.0
I checked lineDataSet.xMin and lineDataSet.xMax. They have valid values.
You need to set below property for not skip 1st and last value
//Set up XAxis into chart.
lineChart.xAxis.axisMinimum = 0
lineChart.xAxis.avoidFirstLastClippingEnabled = NO
lineChart.xAxis.granularity = 1.0
Hope this will helps.
I found a solution. The lost line:
combinedChart.xAxis.forceLabelsEnabled = true
I also changed type of chart from LineChart to CombinedChartView.
Related
I have an issue plotting the x-axis against its corresponding values there is no major customisation done except the values are being plotted on the right axis and axis dependency is set to right
Below is the screenshot
Setup code:
let xAxis = evalutionTrendView?.trendGraphView.xAxis
xAxis?.labelPosition = .bottom
xAxis?.drawGridLinesEnabled = false
xAxis?.drawAxisLineEnabled = true
//xAxis?.axisLineColor = Utilities.axisBaseLineColor
xAxis?.forceLabelsEnabled = true
xAxis?.avoidFirstLastClippingEnabled = false
xAxis?.labelFont = UIFont.SFProText.Regular(12.0)
xAxis?.labelTextColor = Utilities.axisValueColor
xAxis?.granularity = 1
xAxis?.granularityEnabled = true
xAxis?.valueFormatter = XaxisValueFormatter()
let rightAxis = evalutionTrendView?.trendGraphView.rightAxis
rightAxis?.gridColor = Utilities.axisBaseLineColor
rightAxis?.gridLineWidth = 1.0
rightAxis?.axisMaximum = 100
rightAxis?.axisMinimum = 0
rightAxis?.axisLineColor = .clear
rightAxis?.labelFont = UIFont.SFProText.Regular(12.0)
rightAxis?.labelTextColor = Utilities.axisValueColor
evalutionTrendView?.trendGraphView?.leftAxis.enabled = false
final class XaxisValueFormatter: AxisValueFormatter{
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
let date = Date(timeIntervalSince1970: TimeInterval(value))
print("x-axis: \(date.dayMonthSlash), value:\(value)")
return date.dayMonthSlash
}
}
Library code:
https://github.com/danielgindi/Charts
Anyone has faced similar issue using with above library with respect to x-axis alignment ?
I am using Charts by Daniel Gindi
How can I set a String 0 label on x Axis? I want it to show "Now" instead of a Date type.
I've seen the function that helps to format one particular label only, but I can't get how it works. Moreover, I haven't seen any examples of it. So, how does getFormattedLabel(index: Int) work?
This is what I need my xAxis to look like:
Thank you!
You can set your xAxis.valueFormatter to your own custom class and then return now when your x value is 0.
Like:
class ChartValueFormatter: NSObject, IAxisValueFormatter {
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
if value == 0 {
return "Now"
}
let dateFormatter = DateFormatter()
dateFormatter.setLocalizedDateFormatFromTemplate("dd MMM")
dateFormatter.locale = .current
let date = Date(timeIntervalSince1970: value)
return dateFormatter.string(from: date)
}
}
For this to work you need to sort your values based on date and then set then now value timestamp to zero.
It took a while to figure out, but I found a great tutorial on Medium by Spencer Mandrusiak
I needed to make the first label of a String type and all the others should still be Date types.
What I did:
Created an X axis formatting class.
Added an enum with only one label
When returning a value, I return time if there are no custom labels left.
This solution works well for me!
class ChartXAxisFormatter: NSObject, IAxisValueFormatter {
enum CustomLabel: Int {
case firstLabel
var label: String {
switch self {
case .firstLabel: return "Now"
}
}
}
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
let dateFormatterPrint = DateFormatter()
dateFormatterPrint.dateFormat = "hh:mm"
let date = Date(timeIntervalSince1970: value)
let time = dateFormatterPrint.string(from: date)
let intVal = Int(value)
let customLabel = CustomLabel(rawValue: intVal)
return customLabel?.label ?? "\(time)"
}
}
This is a snippet that helps me convert an X axis into timeline and also make the last label on the chart of a String type.
index == count - 2 was used because the label count on X axis was set to 3 by force:
chart.xAxis.setLabelCount(3, force: true)
chart.xAxis.avoidFirstLastClippingEnabled = false
chart.xAxis.forceLabelsEnabled = true
class ChartXAxisFormatter: NSObject, IAxisValueFormatter {
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
if let index = axis?.entries.firstIndex(of: value), let count = axis?.entries.count , index == count - 2 {
return "Now"
}
let dateFormatterPrint = DateFormatter()
dateFormatterPrint.dateFormat = "HH:mm:ss"
let date = Date(timeIntervalSince1970: value)
let time = dateFormatterPrint.string(from: date)
return time
}
}
var dataEntries: [ChartDataEntry] = []
let financialData = data
for chartData in financialData{
let dataEntry = CandleChartDataEntry(x: chartData.date, shadowH: chartData.High, shadowL: chartData.Low, open: chartData.Open, close: chartData.Close)
dataEntries.append(dataEntry)
}
let chartDataSet = CandleChartDataSet(values: dataEntries, label: "")
chartDataSet.axisDependency = .left
chartDataSet.drawValuesEnabled = false
chartDataSet.increasingColor = UIColor.green
chartDataSet.increasingFilled = false
chartDataSet.decreasingColor = UIColor.red
chartDataSet.decreasingFilled = true
chartDataSet.barSpace = 0.25
chartDataSet.shadowColor = UIColor.darkGray
chartDataSet.neutralColor = UIColor.blue
let chartData = CandleChartData(dataSet: chartDataSet)
chartView.data = chartData
let xaxis = chartView.xAxis
xaxis.valueFormatter = axisFormatDelegate
Below is the sample data set that is being received from server and the image showing the chart being displayed.
https://api.cryptowat.ch/markets/gdax/btcusd/ohlc?periods=60
[ CloseTime, OpenPrice, HighPrice, LowPrice, ClosePrice, Volume ]
I need help in fixing the display of data as currently it doesn't resemble a candle stick chart in any way. Can someone please help me in what I am doing wrong here.
CandleStick chart data being displayed in the app
So just in case anyone is having the same problem, i was having issues with the candles too and i found a solution based on this post:
https://github.com/danielgindi/Charts/issues/2742
Create a class for your chartView.xAxis.valueFormatter that supports your entries with your init.
Once you have your results entries, i used the enumerated value for the x on the CandleChartDataEntry
In the stringForValue method inside your class that inherits from IAxisValueFormatter work the way you want to present your string, in my case was dates.
First two points:
//Check nil results
if result != nil {
//Save to Holder for future use
self.historyData = result
// Set the formatter class for the chartView
self.chartView.xAxis.valueFormatter = dateFormatter(elementsForFormatter: self.historyData!)
//Create a new chart data entry
var chartEntries = [ChartDataEntry]()
//Loop results
result?.enumerated().forEach({ (i, element) in
// I'm force unwrapping, but please take care of this don't do me...
let newDataEntryValue = CandleChartDataEntry(x:Double(i),
shadowH: element["high"] as! Double,
shadowL: element["low"] as! Double,
open: element["open"] as! Double,
close: element["close"] as! Double)
chartEntries.append(newDataEntryValue)
})
}
// Do rest of conf. for your chart....
Last point (class implementation):
class dateFormatter: IAxisValueFormatter {
var elements:Array<Dictionary<String,Any>>
init(elementsForFormatter:Array<Dictionary<String,Any>>) {
self.elements = elementsForFormatter
}
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
let formatter = DateFormatter()
formatter.dateStyle = .short
//Get the date based on the value which is the index
if let time = self.elements[Int(value)]["time"] as? Double {
print(time)
let dateString = formatter.string(from: Date(timeIntervalSince1970: TimeInterval(time)))
return dateString
} else {
return ""
}
}
}
Hope this helps someone!
Instead of showing the Double values in my chart I would like to show a String for each value. I still want the chart to draw from the Double values, but I want the label to show a string with a date instead. How to do this?
I´m using Daniel Cohen Gindis library.
Here is the code for my graph:
import UIKit
import Charts
class ViewController: UIViewController {
#IBOutlet var barChartView: BarChartView!
override func viewDidLoad() {
super.viewDidLoad()
//x line values
let tools = ["Saw","Sissor","Axe"
,"Hammer","Tray"]
//y line values
let values = [1.0,2.0,3.0,4.0,5.0]
setChart(tools, values: values, colors: colors)
}
func setChart(xAxisLabels: [String], values: [Double], colors: [UIColor]){
var dataEntries : [BarChartDataEntry] = []
for i in 0..<xAxisLabels.count {
let dataEntry = BarChartDataEntry(value: values[i], xIndex: i )
dataEntries.append(dataEntry)
}
barChartView.leftAxis.axisMinValue = 0.0
barChartView.leftAxis.axisMaxValue = 14.0
barChartView.data = chartData
}
}
You can use the String() method to convert any data type into a string.
For example:
var myDouble: Double = 1.5
print(String(myDouble)) // Prints "1.5"
I don't know if you still need the answer, but this may help somebody who struggles with the same problem :)
First of all, you need to make a ValueFormatter class for your xAxis.
xAxis.valueFormatter = XAxisValueFormatter()
And then you have to put the following in your new class:
class XAxisValueFormatter: NSObject, IAxisValueFormatter {
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
let dateFormatterPrint = DateFormatter()
dateFormatterPrint.dateFormat = "HH:mm:ss"
let date = Date(timeIntervalSince1970: value)
let time = dateFormatterPrint.string(from: date)
return time
}
}
How do I format the data that is shown in the linechart of Charts? By default the data is shown as double, but I want it to be displayed as int.
let pre = [20.0, 4.0, 6.0, 3.0, 12.0, 16.0]
for i in 0..<pre.count {
let preDataEntry = ChartDataEntry(value: pre[i], xIndex: i)
preEntries.append(preDataEntry)
}
let preChartDataSet = LineChartDataSet(yVals: preEntries, label: "Pre")
lineChartView.data = lineChartData
FIXED FOR SWIFT 3
YAxisValueFormatter.swift
import Foundation
import Charts
class YAxisValueFormatter: NSObject, IAxisValueFormatter {
let numFormatter: NumberFormatter
override init() {
numFormatter = NumberFormatter()
numFormatter.minimumFractionDigits = 1
numFormatter.maximumFractionDigits = 1
// if number is less than 1 add 0 before decimal
numFormatter.minimumIntegerDigits = 1 // how many digits do want before decimal
numFormatter.paddingPosition = .beforePrefix
numFormatter.paddingCharacter = "0"
}
/// Called when a value from an axis is formatted before being drawn.
///
/// For performance reasons, avoid excessive calculations and memory allocations inside this method.
///
/// - returns: The customized label that is drawn on the axis.
/// - parameter value: the value that is currently being drawn
/// - parameter axis: the axis that the value belongs to
///
public func stringForValue(_ value: Double, axis: AxisBase?) -> String {
return numFormatter.string(from: NSNumber(floatLiteral: value))!
}
}
create YAxisValueFormatterclass, and assign object to graph leftAxis
// Number formatting of YAxis
chartView.leftAxis.valueFormatter = YAxisValueFormatter()
There are some formatter properties you could use:
valueFormatter in ChartDataSet
formatters in ChartYAxis:
/// the formatter used to customly format the y-labels
public var valueFormatter: NSNumberFormatter?
/// the formatter used to customly format the y-labels
internal var _defaultValueFormatter = NSNumberFormatter()
should be enough