Reputation: 659
I have been learning to use iOS Charts over the past few days and have successfully gotten to them work when dealing with 'single' data called in from an API.
However I am now stuck because I want to pull in multiple data from an array.
My aim is to create a Bar Chart based on the winning_streak
of each user_name
in the array below:
["leagueStats": {
winningStreak = (
{
id = 2;
"user_name" = Dicky;
"winning_streak" = 5;
},
{
id = 6;
"user_name" = G;
"winning_streak" = 2;
},
{
id = 5;
"user_name" = Sultan;
"winning_streak" = 0;
}
);
}
]
This is my code that retrieves the API:
This is where I need help - Do I need to produce some kind of loop? In the answer supplied the amount of users to appear in the graph is pre-programmed.
With my current code below it only picks out the first object in the array. How do I get it to cycle through the array and populate the desired variables?
if let dict = json?["leagueStats"] as? [String:AnyObject] {
// WINNING STREAK
if let dataWinStreak = dict["winningStreak"] as? [[String : AnyObject]] {
let newdictWinStreak = dataWinStreak.first! // I'm guess this needs to be removed and this section re-structured?
let tempWinStreakNumber = newdictWinStreak ["winning_streak"] as? String
let tempWinStreakNewNumber = Int(tempWinStreakNumber!)
let doubleWinStreak = Double(tempWinStreakNewNumber!)
self.winStreak = doubleWinStreak
self.winningStreak = ["Wins"]
let games = [self.winStreak]
self.setWinStreakChart(dataPoints: self.winningStreak, values: games)
}
However this code above only pulls in information from the first record in the array to use, 5
.
I want to be able to produce 3 different columns, Dicky
, G
, Sultan
, with the corresponding values of 5
, 2
, and 0
.
This is my code for displaying the Bar Chart - currently just displaying 1 column, showing 5
.
func setWinStreakChart(dataPoints: [String], values: [Double]){
let formato:WinningStreakFormatter = WinningStreakFormatter()
let xaxis:XAxis = XAxis()
winningStreakBarChart.noDataText = "you need to provide some data for the chart."
var dataEntries: [BarChartDataEntry] = Array()
for i in 0..<dataPoints.count {
let dataEntry = BarChartDataEntry(x: Double(i), y: values[i])
dataEntries.append(dataEntry)
formato.stringForValue (Double(i), axis: xaxis)
}
xaxis.valueFormatter = formato
winningStreakBarChart.xAxis.valueFormatter = xaxis.valueFormatter
let chartDataSet = BarChartDataSet(values: dataEntries, label: "Games Played")
let chartData = BarChartData(dataSets: [chartDataSet])
chartData.addDataSet(chartDataSet)
winningStreakBarChart.data = chartData
winningStreakBarChart.xAxis.granularityEnabled = true
winningStreakBarChart.xAxis.granularity = 1.0
self.winningStreakBarChart.xAxis.labelPosition = XAxis.LabelPosition.bottom
}
This is what I have:
Ideally, what I want is the label 'Win Streak' to be the user_name
from the API, then the legend Games _Played
to say Winning Streak
. In this particular instance, I want 3 columns for the 3 user_names in the array.
Once this is done, as a secondary objective I want to add another dataset for Losing Streak
which would be grouped by the same user_name
.
Could someone please show me how to do this? Thank you
Upvotes: 3
Views: 2298
Reputation: 558
WinningStreakFormatter
class is used to format xAxis labels, here I have used an approach of reusing the data from chart object as result WinningStreakFormatter
have a weak reference to the chart view. So using this approach we can have data to be held by chart view rather than keeping an additional copy with WinningStreakFormatter
import Foundation
import Charts
class WinningStreakFormatter: NSObject, IAxisValueFormatter {
weak var _chartView : BarChartView!
init(chartView : BarChartView) {
self._chartView = chartView
}
public func stringForValue(_ value: Double, axis: AxisBase?) -> String {
let barChartData : IChartDataSet = (self._chartView.barData?.dataSets.first)!
let barChartDataEntry : ChartDataEntry = barChartData.entryForIndex(Int(value))!
return barChartDataEntry.data as! String
}
}
Refer the code below in order to prepare the proposed chart, In below code chartView is basically the BarChartView
type instance variable. Also, I have used the same data structure that you have in your API, you can simply replace dataPoints with your parsed data structure.
self.chartView.drawBarShadowEnabled = false
self.chartView.drawValueAboveBarEnabled = true
self.chartView.chartDescription?.enabled = false
let xAxis : XAxis = self.chartView.xAxis;
xAxis.labelFont = UIFont(name: "HelveticaNeue-Light", size: 10.0)!
xAxis.labelTextColor = UIColor.black
xAxis.drawAxisLineEnabled = false
xAxis.drawGridLinesEnabled = true
xAxis.granularity = 1;
xAxis.labelPosition = .bottom
xAxis.valueFormatter = WinningStreakFormatter(chartView: self.chartView)
let yAxisLeft : YAxis = self.chartView.leftAxis
yAxisLeft.axisMinimum = 0.0
let yAxisRight : YAxis = self.chartView.rightAxis
yAxisRight.axisMinimum = 0.0
let l : Legend = self.chartView.legend;
l.horizontalAlignment = Legend.HorizontalAlignment.left
l.verticalAlignment = Legend.VerticalAlignment.bottom
l.orientation = Legend.Orientation.horizontal
l.drawInside = false
l.form = Legend.Form.square
l.formSize = 9.0
l.font = UIFont(name: "HelveticaNeue-Light", size: 11.0)!
l.xEntrySpace = 4.0
//Data Structure built for each user for winning streak, you can use your parsing logic to prepare the same
let winningStreakDM1 : [String : Any] = [
"id" : 2,
"user_name" : "Dicky",
"winning_streak" : 5
]
let winningStreakDM2 : [String : Any] = [
"id" : 6,
"user_name" : "G",
"winning_streak" : 2
]
let winningStreakDM3 : [String : Any] = [
"id" : 5,
"user_name" : "Sultan",
"winning_streak" : 0
]
//Array of the each user winning streak dictionary.
let dataPoints = [winningStreakDM1, winningStreakDM2, winningStreakDM3]
var values = [BarChartDataEntry]()
for i in 0..<dataPoints.count {
let xValue = Double(i)
let yValue = Double(dataPoints[i]["winning_streak"] as! Int)
let barChartDataEntry = BarChartDataEntry(x: xValue, y: yValue, data: dataPoints[i]["user_name"] as AnyObject)
values.append(barChartDataEntry)
}
let barChartDataSet = BarChartDataSet(values: values, label: "Winning Streak")
barChartDataSet.colors = ChartColorTemplates.material()
let barChartData = BarChartData(dataSet: barChartDataSet)
barChartData.setValueFont(UIFont.systemFont(ofSize: 12.0))
self.chartView.data = barChartData
Upvotes: 3