I am using danielgindi
/
Charts for creating line chart. When Line chart data has same values, only the last drawn line showing. Other lines are hidden behind the last drawn line. Is there any way to show all lines.
image: 'fff' and 'User B' is hidden behind 'User C', they all have number of activities equal to zero
Line chart initialisation
func commonInit() {
guard let view = loadViewFromNib() else { return }
view.frame = self.bounds
self.addSubview(view)
lblXAxis.text = "Days"
lblYAxis.text = "Number of Activities"
lblYAxis.transform = CGAffineTransform(rotationAngle: -CGFloat.pi / 2)
self.roundAllCorners(radius: 6)
let valFormatter = NumberFormatter()
valFormatter.numberStyle = .none
valFormatter.maximumFractionDigits = 0
viewProgressLineChart.leftAxis.valueFormatter = DefaultAxisValueFormatter(formatter: valFormatter)
viewProgressLineChart.leftAxis.granularity = 1
viewProgressLineChart.xAxis.granularity = 1
viewProgressLineChart.xAxis.labelCount = 11
viewProgressLineChart.xAxis.avoidFirstLastClippingEnabled = false
viewProgressLineChart.xAxis.labelPosition = .bottom
viewProgressLineChart.chartDescription?.text = ""
viewProgressLineChart.xAxis.labelTextColor = UIColor.onPrimary
viewProgressLineChart.leftAxis.labelTextColor = UIColor.onPrimary
viewProgressLineChart.rightAxis.labelTextColor = UIColor.onPrimary
viewProgressLineChart.clipValuesToContentEnabled = true
viewProgressLineChart.legend.enabled = false
viewProgressLineChart.rightAxis.enabled = false
viewProgressLineChart.animate(xAxisDuration: 0.8)
}
This is how data is given to line chart,
func updateGraph(users: [User]){
let data = LineChartData()
for (index,user) in users.enumerated(){
let userColor = UIColor.selectedColors[index]
userAndStatusColorArray.append(UserAndStatusColor(name: user.name ?? "user", color: userColor))
var lineChartEntry = [ChartDataEntry]()
if user.progress != nil{
for progress in user.progress!{
let chartData = ChartDataEntry(x: Double(progress.day), y: Double(progress.activitiesCompleted!))
lineChartEntry.append(chartData)
}
let chartDataSet = LineChartDataSet(entries: lineChartEntry)
chartDataSet.colors = [userColor]
chartDataSet.circleColors = [userColor]
chartDataSet.circleRadius = 3
chartDataSet.drawValuesEnabled = false
data.addDataSet(chartDataSet)
}
}
viewPODProgressLineChart.viewProgressLineChart.data = data
}
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'm new to Swift and I'm trying to create bar chart. I manage to create a chart but for some reason moveViewToX() does not work as expected - it does not scroll to the last x values. Here is my relevant function to create a chart:
func createBarView() {
// Set basic parameters
barChartView.xAxis.labelTextColor = .black
barChartView.leftAxis.labelTextColor = .black
barChartView.leftAxis.axisMinimum = 0
barChartView.xAxis.labelPosition = XAxis.LabelPosition.bottom
barChartView.xAxis.labelRotationAngle = 0
barChartView.xAxis.granularity = 1
barChartView.xAxis.labelFont = UIFont.systemFont(ofSize: 20.0, weight: .regular)
barChartView.xAxis.drawGridLinesEnabled = false
barChartView.rightAxis.drawGridLinesEnabled = false
barChartView.leftAxis.drawGridLinesEnabled = false
barChartView.rightAxis.enabled = false
barChartView.leftAxis.enabled = false
barChartView.xAxis.labelPosition = .bottom
barChartView.clipsToBounds = true
barChartView.layer.cornerRadius = 10
barChartView.legend.enabled = false
barChartView.animate(yAxisDuration: 1.3, easingOption: .easeInOutQuart)
barChartView.scaleYEnabled = false
barChartView.scaleXEnabled = false
barChartView.pinchZoomEnabled = false
barChartView.doubleTapToZoomEnabled = false
//Get X (days) and Y data (calories)
let count = realm.objects(WorkoutData.self).count
for i in 0 ..< count {
let graphDates = realm.objects(WorkoutData.self)[i].date
allDates.append(graphDates)
let calendarDate = Calendar.current.dateComponents([.day, .year, .month], from: graphDates)
graphDays.append(String(calendarDate.day!)) // Get days array for xAxis
let graphCalories = realm.objects(WorkoutData.self)[i].calories
visosKalorijos.append(graphCalories) // Get calories array for yAxis
}
//Supply data for BarChartDataEntry
var entries = [BarChartDataEntry]()
for i in 0 ..< count { // dataPoints
let dataEntry = BarChartDataEntry(x: Double(i), y: Double(visosKalorijos[i]))
entries.append(dataEntry) //// Get x:y data
}
//Set labels of xAxis (to show days of the month)
barChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: graphDays)
// Create dataset
let set = BarChartDataSet(entries: entries, label: "-")
set.colors = ChartColorTemplates.solid()
set.valueFont = UIFont.systemFont(ofSize: 16)
let data = BarChartData(dataSet: set)
data.barWidth = Double(0.4)
barChartView.data = data
// Set visibility
barChartView.setVisibleXRangeMaximum(7)
barChartView.moveViewToX(Double(count))
}
When function is executed I can see only up to 17th day, but there are more days on the xAxis if I scroll.
After view is loaded I need to scroll to the end.
The last part - // Set visibility is where the problem is - it does not scroll automatically to the last x value. What Am I doing wrong? Thanks for your help.
After some time I figured this out. Last step //Set visibility needs delay of 0.1s:
barChartView.setVisibleXRangeMaximum(7)
let when = DispatchTime.now() + 0.1
DispatchQueue.main.asyncAfter(deadline: when) {
self.barChartView.moveViewToX(Double(self.count))
}
Hopefully this will help someone in the future :)
I have the following line chart with 2 datasets.
One data set is dependent on the left yAxis the other one on the right yAxis.
Now i want them both to have the zero value in the same line.
The other values are ok to not be aligned.
How can i do that?
Code:
let speedLine = LineChartDataSet(values: speedEntries, label: "Speed")
speedLine.colors = [UIColor.white]
speedLine.drawCirclesEnabled = false
speedLine.axisDependency = .left
let powerLine = LineChartDataSet(values: powerEntries, label: "Power")
powerLine.colors = [UIColor.green]
powerLine.drawCirclesEnabled = false
powerLine.axisDependency = .right
let data = LineChartData()
data.addDataSet(speedLine)
data.addDataSet(powerLine)
chartView.data = data
chartView.xAxis.labelTextColor = UIColor.white
chartView.xAxis.labelCount = 20
chartView.leftAxis.labelTextColor = UIColor.white
chartView.rightAxis.labelTextColor = UIColor.green
chartView.legend.textColor = UIColor.white
chartView.rightAxis.axisMinimum = -80.0
chartView.chartDescription?.text = ""
Since you have:
chartView.rightAxis.axisMinimum = -80.0
You might need to do this as well:
chartView.leftAxis.axisMinimum = -80.0
I think there is still no resolution for this problem but we can still hide yAxis right side.
let yAxisLeft = chartView.leftAxis
yAxisLeft.drawGridLinesEnabled = true
yAxisLeft.gridColor = UIColor(hex: "DCE5EE")
yAxisLeft.labelFont = Theme.Font.main(ofSize: 9, weight: .regular)
yAxisLeft.labelXOffset = 2
yAxisLeft.labelTextColor = Theme.Color.white
yAxisLeft.axisLineColor = UIColor(hex: "DCE5EE")
yAxisLeft.drawAxisLineEnabled = false
yAxisLeft.labelCount = 4
yAxisLeft.axisMinLabels = 1
yAxisLeft.enabled = true
yAxisLeft.axisMinimum = 0
let yAxisRight = chartView.rightAxis
yAxisRight.drawGridLinesEnabled = false
yAxisRight.labelFont = Theme.Font.main(ofSize: 9, weight: .regular)
yAxisRight.labelXOffset = -2
yAxisRight.labelTextColor = Theme.Color.white
yAxisRight.drawAxisLineEnabled = false
yAxisRight.labelCount = 4
yAxisRight.axisMinLabels = 1
yAxisRight.enabled = true
yAxisRight.axisMinimum = 0
This is the final result:
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.