I have negative values in my line chart using ios-charts. Positive values are displayed but negative values are clipped at 0. I have set the left and right axes not to start at 0 but no help.
LineChart1.leftAxis.startAtZeroEnabled = false
LineChart1.rightAxis.startAtZeroEnabled = false
Any ideas? TIA.
Code snippet below.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.navigationController?.navigationBar.translucent = false
self.title = "Line Chart 1"
LineChart1.bounds = CGRectMake(-20, -20, 275, 250)
LineChart1.data = getMyData()
LineChart1.drawBordersEnabled = false
LineChart1.legend.enabled = false
LineChart1.leftAxis.startAtZeroEnabled = false
LineChart1.rightAxis.startAtZeroEnabled = false
LineChart1.xAxis.setLabelsToSkip(0)
LineChart1.xAxis.drawGridLinesEnabled = false
LineChart1.leftAxis.drawGridLinesEnabled = true
LineChart1.rightAxis.drawLabelsEnabled = false
LineChart1.animate(xAxisDuration: 0.3)
LineChart1.animate(yAxisDuration: 0.3)
LineChart1.setNeedsDisplay()
}
func getMyData() -> LineChartData {
var xVals = ["2008","2009","2010","2011","2012"]
var courses: [ChartDataEntry] = []
courses.append(ChartDataEntry(value: 3, xIndex: 0))
courses.append(ChartDataEntry(value: -40, xIndex: 1))
courses.append(ChartDataEntry(value: 4, xIndex: 2))
courses.append(ChartDataEntry(value: 4, xIndex: 3))
courses.append(ChartDataEntry(value: 3, xIndex: 4))
let bcds = LineChartDataSet(yVals: courses, label: "")
bcds.valueTextColor = UIColor.blackColor()
return LineChartData(xVals: xVals, dataSet: bcds)
}
You should call notifyDataSetChanged() after setting startAtZeroEnabled - like in the sample app.
The chart does not know of a change in a property like startAtZeroEnabled on an inner component, so you have to tell it.
And because min/max are calculated in notifyDataSetChanged according to startAtZeroEnabled, that's a case where you have to notify, and just setNeedsDisplay...
Related
I'm learning how to create charts and I'm at the point where I need to use more complex data. I created charts where the usual ranges were used.
This is what my chart looks like now
What I need to end up with.
I don't know how to change the axes data according to the array:
items = [AgeItem(ageGroup: ">60", iqLevel: 95),
AgeItem(ageGroup: "45-60", iqLevel: 118),
AgeItem(ageGroup: "35-44", iqLevel: 141),
AgeItem(ageGroup: "25-34", iqLevel: 106),
AgeItem(ageGroup: "18-24", iqLevel: 126),
AgeItem(ageGroup: "16-17", iqLevel: 100)]
The task is to create a graph that will display how many points a person from a certain age group scored when passing the test. Y-axis - age group, X-axis - test points. I also need to add a "you" chart bar that will stand out from the others.
Here is my graph code:
override func awakeFromNib() {
super.awakeFromNib()
self.setup(barLineChartView: chartView)
chartView.delegate = self
chartView.drawBarShadowEnabled = false
chartView.drawValueAboveBarEnabled = true
chartView.maxVisibleCount = 60
let xAxis = chartView.xAxis
xAxis.labelPosition = .bottom
xAxis.labelFont = .systemFont(ofSize: 10)
xAxis.drawAxisLineEnabled = true
xAxis.granularity = 10
xAxis.labelTextColor = .white
let leftAxis = chartView.leftAxis
leftAxis.labelFont = .systemFont(ofSize: 10)
leftAxis.drawAxisLineEnabled = true
leftAxis.drawGridLinesEnabled = true
leftAxis.axisMinimum = 0
leftAxis.labelTextColor = .white
let rightAxis = chartView.rightAxis
rightAxis.enabled = true
rightAxis.labelFont = .systemFont(ofSize: 10)
rightAxis.drawAxisLineEnabled = true
rightAxis.axisMinimum = 0
rightAxis.labelTextColor = .white
chartView.fitBars = true
chartView.animate(yAxisDuration: 2.5)
self.setDataCount(Int(12) + 1, range: UInt32(190))
}
func setDataCount(_ count: Int, range: UInt32) {
let barWidth = 9.0
let spaceForBar = 10.0
let yVals = (0..<count).map { (i) -> BarChartDataEntry in
let mult = range + 1
let val = Double(arc4random_uniform(mult))
return BarChartDataEntry(x: Double(i)*spaceForBar, y: val)
}
let set1 = BarChartDataSet(entries: yVals)
set1.drawIconsEnabled = false
let data = BarChartData(dataSet: set1)
data.setValueFont(UIFont.poppins(size: 12))
data.barWidth = barWidth
data.setValueTextColor(.white)
chartView.data = data
}
func setup(barLineChartView chartView: BarLineChartViewBase) {
chartView.chartDescription.enabled = false
chartView.dragEnabled = true
chartView.setScaleEnabled(true)
chartView.pinchZoomEnabled = false
// ChartYAxis *leftAxis = chartView.leftAxis;
let xAxis = chartView.xAxis
xAxis.labelPosition = .bottom
chartView.rightAxis.enabled = false
}
I am trying to simple line chart. Chart is coming fine and I want to add values/names for every point of x and y axis.
See the following image, this is is comming , but I want to add/show values in x and y axis.
For example: Check in my example code, I mentioned months and unitSold values.
in X axis I wants to show months names and Y axis and I wants to show some unit sold values.
How can I do or show values in x and y axis?
import UIKit
import Charts
class ViewController: UIViewController {
var dataEntries: [ChartDataEntry] = []
// var chartDataBeanArray = [ChartDataBean]()
let months = ["Jan" , "Feb", "Mar", "Apr", "May", "June", "July", "August", "Sept", "Oct", "Nov", "Dec"]
let unitsSold = [24.0,43.0,56.0,23.0,56.0,68.0,48.0,120.0,41.0,34.0,55.9,12.0,34.0]
#IBOutlet weak var chartViewOutlet: LineChartView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setChart(months, values: unitsSold)
}
func setChart(_ dataPoints: [String], values: [Double]) {
print(values)
print(dataPoints)
chartViewOutlet.noDataText = "No data available!"
for i in 0..<values.count {
print("chart point : \(values[i])")
let dataEntry = ChartDataEntry(x: Double(i), y: values[i])
dataEntries.append(dataEntry)
}
let line1 = LineChartDataSet(entries: dataEntries, label: "Units Consumed")
line1.colors = [NSUIColor.blue]
line1.mode = .cubicBezier
line1.cubicIntensity = 0.2
let gradient = getGradientFilling()
line1.fill = Fill.fillWithLinearGradient(gradient, angle: 90.0)
line1.drawFilledEnabled = true
let data = LineChartData()
data.addDataSet(line1)
chartViewOutlet.data = data
chartViewOutlet.setScaleEnabled(false)
chartViewOutlet.animate(xAxisDuration: 1.5)
chartViewOutlet.drawGridBackgroundEnabled = false
chartViewOutlet.xAxis.drawAxisLineEnabled = false
chartViewOutlet.xAxis.drawGridLinesEnabled = false
chartViewOutlet.leftAxis.drawAxisLineEnabled = false
chartViewOutlet.leftAxis.drawGridLinesEnabled = false
chartViewOutlet.rightAxis.drawAxisLineEnabled = false
chartViewOutlet.rightAxis.drawGridLinesEnabled = false
chartViewOutlet.legend.enabled = false
chartViewOutlet.xAxis.enabled = false
chartViewOutlet.leftAxis.enabled = false
chartViewOutlet.rightAxis.enabled = false
chartViewOutlet.xAxis.drawLabelsEnabled = false
}
/// Creating gradient for filling space under the line chart
private func getGradientFilling() -> CGGradient {
// Setting fill gradient color
let coloTop = UIColor(red: 141/255, green: 133/255, blue: 220/255, alpha: 1).cgColor
let colorBottom = UIColor(red: 230/255, green: 155/255, blue: 210/255, alpha: 1).cgColor
// Colors of the gradient
let gradientColors = [coloTop, colorBottom] as CFArray
// Positioning of the gradient
let colorLocations: [CGFloat] = [0.7, 0.0]
// Gradient Object
return CGGradient.init(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: gradientColors, locations: colorLocations)!
}
}
EDIT : After adding following code suggested by #marc
chartViewOutlet.xAxis.enabled = true
chartViewOutlet.leftAxis.enabled = true
this is now showing chart.
Now I wants to show months values in bottom (x axis)...how to show it?
You can find source code here if you want to check it: https://drive.google.com/file/d/1vkPqktZ3mX3q9f75-bihVYeublwc2dXE/view?usp=sharing
Add following code in your project.
func setChart(dataPoints: [String], values: [Double]) {
for i in 0 ..< dataPoints.count {
dataEntries.append(ChartDataEntry(x: Double(i), y: values[i]))
}
let lineChartDataSet = LineChartDataSet(entries: dataEntries, label: "Units Consumed")
lineChartDataSet.axisDependency = .left
lineChartDataSet.setColor(UIColor.black)
lineChartDataSet.setCircleColor(UIColor.black) // our circle will be dark red
lineChartDataSet.lineWidth = 1.0
lineChartDataSet.circleRadius = 3.0 // the radius of the node circle
lineChartDataSet.fillAlpha = 1
lineChartDataSet.fillColor = UIColor.black
lineChartDataSet.highlightColor = UIColor.white
lineChartDataSet.drawCircleHoleEnabled = true
var dataSets = [LineChartDataSet]()
dataSets.append(lineChartDataSet)
let lineChartData = LineChartData(dataSets: dataSets)
chartViewOutlet.data = lineChartData
chartViewOutlet.rightAxis.enabled = false
chartViewOutlet.xAxis.drawGridLinesEnabled = false
chartViewOutlet.xAxis.labelPosition = .bottom
chartViewOutlet.xAxis.valueFormatter = IndexAxisValueFormatter(values: dataPoints)
chartViewOutlet.legend.enabled = true
}
Output:
This works 100%. Try it.
I am using Charts v3.2.2 framework by danielgindi for iOS and macOS to draw a RadarChartView. There is a github repository that provides an example xcode project including Playgrounds. One is for RadarChartView.
Following the example I can set RadarChartData with two different RadarChartDataSets
var chartView = RadarChartView(frame: rect)
let data = RadarChartData(dataSets: [set1, set2])
chartView.data = data
It shows a chart like this:
The green labels set to x-axis are numbers from 0.0 to 4.0, but they should be string labels.
I cannot figure out how to set these labels that should be drawn around the RadarChart at the end of each web line. I guess it should be something like this:
data.setLabels("London", "Paris", "Berlin", "New York", "Tokio")
But this isn't working although it is a feature of class RadarChartData to set the desired labels.
Can somebody help me with that issue?
EDIT: complete code example
import Cocoa
import Charts
import PlaygroundSupport
let r = CGRect(x: 0, y: 0, width: 400, height: 400)
var chartView = RadarChartView(frame: r)
// General settings
chartView.webColor = NSUIColor.lightGray
chartView.innerWebColor = NSUIColor.lightGray
chartView.webAlpha = 1.0
// xAxis settings
let xAxis = chartView.xAxis
xAxis.xOffset = 0.0
xAxis.yOffset = 0.0
xAxis.labelTextColor = NSUIColor.green
xAxis.drawLabelsEnabled = true
// yAxis settings
let yAxis = chartView.yAxis
yAxis.labelCount = 5
yAxis.axisMinimum = 0.0
yAxis.axisMaximum = 80.0
yAxis.drawLabelsEnabled = true
// Legend settings
let legend = chartView.legend
// ... (irrelevant)
// Description
chartView.chartDescription?.enabled = true
chartView.chartDescription?.text = "Radar demo"
chartView.chartDescription?.textColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
// RadarChartDataEntry
let mult = 80.0
let min = 20.0
let cnt = 5
var entries1 = [RadarChartDataEntry]()
var entries2 = [RadarChartDataEntry]()
for i in 1...cnt
{
let values1 = (Double(arc4random_uniform(UInt32(mult))) + min)
entries1.append(RadarChartDataEntry(value: values1, data: "a" as AnyObject))
let values2 = (Double(arc4random_uniform(UInt32(mult))) + min)
entries2.append(RadarChartDataEntry(value: values2, data: "b" as AnyObject))
}
// RadarChartDataSet
let set1 = RadarChartDataSet(entries: entries1, label: "Last Week")
set1.drawFilledEnabled = true
set1.fillAlpha = 0.7
set1.lineWidth = 2.0
set1.drawHighlightCircleEnabled = true
set1.setDrawHighlightIndicators(false)
let set2 = RadarChartDataSet(entries: entries2, label: "This Week")
set2.drawFilledEnabled = true
set2.fillAlpha = 0.7
set2.lineWidth = 2.0
set2.drawHighlightCircleEnabled = true
set2.setDrawHighlightIndicators(false)
// RadarChartData
let data = RadarChartData(dataSets: [set1, set2])
data.setLabels("London", "Paris", "Berlin", "New York", "Tokio")
data.setDrawValues ( true )
data.setValueTextColor( NSUIColor.white )
chartView.data = data
chartView.animate(xAxisDuration: 2.0, yAxisDuration: 2.0, easingOption: .easeInBounce)
// show chartView
PlaygroundPage.current.liveView = chartView
You need to override IAxisValueFormatter func stringForValue(_ value: Double, axis: AxisBase?) -> String {} function.
Like below:
Step1: Customize your xAxis with custom formatter.
let xValues = ["X1", "X2", "X3", "X4", "X5", "X6", "X7", "X8", "X9", "X10"]
let chartFormatter = RadarChartFormatter(labels: xValues)
let xAxis = XAxis()
xAxis.valueFormatter = chartFormatter
self.xAxis.valueFormatter = xAxis.valueFormatter
Step2: Implement Custom formatter with below method.
private class RadarChartFormatter: NSObject, IAxisValueFormatter {
var labels: [String] = []
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
if Int(value) < labels.count {
return labels[Int(value)]
}else{
return String("")
}
}
init(labels: [String]) {
super.init()
self.labels = labels
}
}
You will get below output in your RadarCharView:
Hope this will help you to get your custom labels on Radar chart!
I am trying to setup a line chart with one fill colour but for some reason, the fill colour is faded.
Example
Both the random view I have added to middle of screen and the fill colour of the line chart are set to be red, but for some reason the fill colour of the chart is faded.
Can see code here
#IBOutlet var liveChart : LineChartView!
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Chart Tests"
configureChart(chart: liveChart)
var xAxis = [String]()
var yAxis = [Double]()
for _ in 0..<10
{
xAxis.append("")
let yVal = Double(randomBetweenNumbers(firstNum: 1.0, secondNum: 100.0))
yAxis.append(yVal)
}
setData(xAxisArray: xAxis, yAxisArray: yAxis, chart: liveChart)
let testView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
testView.center = view.center
testView.backgroundColor = UIColor.red
view.addSubview(testView)
}
func randomBetweenNumbers(firstNum: CGFloat, secondNum: CGFloat) -> CGFloat{
return CGFloat(arc4random()) / CGFloat(UINT32_MAX) * abs(firstNum - secondNum) + min(firstNum, secondNum)
}
func configureChart(chart : LineChartView)
{
chart.chartDescription?.text = ""
chart.noDataText = "Loading Data"
chart.backgroundColor = UIColor.clear
chart.drawGridBackgroundEnabled = false
chart.dragEnabled = true
chart.rightAxis.enabled = false
chart.leftAxis.enabled = true
chart.doubleTapToZoomEnabled = false
chart.legend.enabled = false
chart.pinchZoomEnabled = true
chart.highlightPerTapEnabled = false
chart.highlightPerDragEnabled = false
chart.xAxis.enabled = false
chart.leftAxis.drawAxisLineEnabled = false
chart.leftAxis.drawGridLinesEnabled = false
chart.leftAxis.labelCount = 5
chart.leftAxis.forceLabelsEnabled = true
}
func setData(xAxisArray : [String], yAxisArray : [Double], chart : LineChartView)
{
var yVals1 : [ChartDataEntry] = [ChartDataEntry]()
if(xAxisArray.count > 0)
{
for i in 0 ..< xAxisArray.count
{
let chartEntry = ChartDataEntry(x: Double(i), y: yAxisArray[i], data: nil)
yVals1.append(chartEntry)
}
}
let set1: LineChartDataSet = LineChartDataSet(values: yVals1, label: "")
set1.fillColor = UIColor.red
set1.drawFilledEnabled = true
set1.drawCirclesEnabled = false
let data = LineChartData()
data.addDataSet(set1)
liveChart.data = data
}
Is there a way to fix this? Or is this just the way the fill colour of the chart works?
Edit:
I am using
https://github.com/danielgindi/Charts
I assume you use this library: https://github.com/kevinbrewster/SwiftCharts
So the LineChartView automatically set alpha for the fill color: https://github.com/kevinbrewster/SwiftCharts/blob/master/SwiftCharts/LineChart.swift#L758
try to set fillAlpha property of the data set
I have a combined chart that uses a line and bar chart to show yValues.
In some instances the line and bar chart values will overlap, is there a way to set the vertical spacing of the labels for the yValues so that they're not on top of each other (like Jan to Oct in the image)?
Combined Chart Image
I'm using the Charts framework (formerly ios-charts), here is the code to setup the CombineChartView:
let xValues = getXAxisLabelsForYear(year)
let runningTotalsByMonth = getRunningTotalByMonthForYear(year)!
var yValsBar = [BarChartDataEntry]()
var yValsLine = [ChartDataEntry]()
for i in 0 ..< xValues.count {
let yBarDataEntry = BarChartDataEntry(value: monthlyWinnings[i], xIndex: i)
yValsBar.append(yBarDataEntry)
let yLineDataEntry = ChartDataEntry(value: runningTotalsByMonth[i], xIndex: i)
yValsLine.append(yLineDataEntry)
}
let barChartDataSet = BarChartDataSet(yVals: yValsBar, label: "Monthly Winnings")
//setup bar chart
var barChartColors = [UIColor]()
for i in monthlyWinnings {
if i >= 0.0 {
barChartColors.append(myGreen)
} else {
barChartColors.append(UIColor.redColor())
}
}
barChartDataSet.colors = barChartColors
barChartDataSet.barShadowColor = UIColor.clearColor()
barChartDataSet.valueFont = UIFont.systemFontOfSize(10.0)
//setup line chart
let lineChartDataSet = LineChartDataSet(yVals: yValsLine, label: "Cumulative Winnings")
var lineChartColors = [UIColor]()
for i in runningTotalsByMonth {
if i >= 0.0 {
lineChartColors.append(myGreen)
} else {
lineChartColors.append(UIColor.redColor())
}
}
lineChartDataSet.colors = lineChartColors
lineChartDataSet.circleColors = [UIColor.blueColor()]
lineChartDataSet.drawCircleHoleEnabled = false
lineChartDataSet.circleRadius = 5
lineChartDataSet.lineWidth = 2
lineChartDataSet.valueFont = UIFont.systemFontOfSize(10.0)
//combine data
let data = CombinedChartData(xVals: xValues)
data.barData = BarChartData(xVals: xValues, dataSet: barChartDataSet)
data.lineData = LineChartData(xVals: xValues, dataSet: lineChartDataSet)
combinedChartView.data = data
//format the chart
combinedChartView.xAxis.setLabelsToSkip(0)
combinedChartView.xAxis.labelPosition = .Bottom
combinedChartView.descriptionText = ""
combinedChartView.rightAxis.drawLabelsEnabled = false
combinedChartView.rightAxis.drawGridLinesEnabled = false
combinedChartView.drawGridBackgroundEnabled = false
combinedChartView.leftAxis.drawZeroLineEnabled = true
combinedChartView.xAxis.drawGridLinesEnabled = false
combinedChartView.xAxis.wordWrapEnabled = true
You can draw bar chart values below the top of the bar using
chartView.drawValueAboveBarEnabled = false
and setting some color
barChartDataSet.valueTextColor = UIColor.someColor()
Will look like this:
See my comment above, but something like this may work if you're not using auto layout:
let labelA = UILabel()
let labelB = UILabel()
let padding: CGFloat = 5.0 // or whatever
if CGRectIntersectsRect(labelA.frame, labelB.frame) {
// If the minY of labelA is <= labelB's that means labelA is ABOVE labelB
if labelA.frame.minY <= labelB.frame.minY {
// Set it above, with some (optional) padding
labelA.frame.origin.y = labelB.frame.origin.y - padding - labelA.frame.height
} else {
labelB.frame.origin.y = labelA.frame.origin.y - padding - labelB.frame.height
}
}
Of course you'll need additional code for checking if it's too high and other edge cases.