1

Objective

I'm trying to display data from two sets (ACTIVE and REST) in a bar chart. The sets are alternating (meaning there is one ACTIVE interval, followed by a REST interval, etc...). Rather, there is alwats one REST set between every two ACTIVE sets.

The code I've used is below, for reference. I am, however, running into problems with the bar positions and spacing.

Issue: centering bar at x-value

First issue, the bar is not centered at the corresponding x-value. In the example below, the first orange bar has x = 1.

enter image description here

It clearly starts at value 1 on the x axis (its leftmost side corresponds to about 1), but I want it to be centered around the 1 value on the x-axis

Issue: bar spacing

For some reason, the bars intersection and the spacing is not equal (see screenshot). Note the white space between bar 2 and 3, and the absence of space between bar 1 and 2.

The relevant code here is :

let barWidth = 1.0
let barSpace = 0.10
let groupSpace = 0.1

chartData.groupBars(fromX: 1, groupSpace: groupSpace, barSpace: barSpace)
chartData.barWidth = barWidth

Indexing bars and BarChartDataEntry

Each set (REST and ACTIVE) comes from a different array of values.

If I press on the 1st REST bar, I would like to obtain the corresponding value of 0. on the 1st ACTIVE bar, the value 0 also. 2nd ACTIVE bar, value 1...

However, in chartValueSelected, using the entry.x value gives the bar's x-position on the axis (NOT the x value I've set in the code), which is casing errors.

How can I get the value of the selected bar's index in the set it belongs to ?

Code

//
//  MARK: Chart Setup
//
func setupBarChart() {

    let intervals = self.session!.getIntervals()

    //  Set chart delegate
    intervalBarChartView.delegate = self

    //
    // Create pairs (x, y) of values 
    //
    var values_ACTIVE : [BarChartDataEntry] = []
    var values_REST   : [BarChartDataEntry] = []

    for i in 0...(intervals.count - 1) {

        let newValue_ACTIVE    = intervals[i].duration!.doubleValue
        //            let newIndex_ACTIVE       = Double(2*i+1)
        let newIndex_ACTIVE      = Double(i)

        values_ACTIVE += [BarChartDataEntry(x: newIndex_ACTIVE, y: newValue_ACTIVE)]

        if i < (intervals.count - 1) {

            let newValue_REST      = (intervals[i+1].startTime!.doubleValue) - intervals[i].getEndTime()!
            //                let newIndex_REST         = Double(2*i+2)
            let newIndex_REST         = Double(i)

            values_REST += [BarChartDataEntry(x: newIndex_REST, y: newValue_REST)]

        }

    }

    //  Create data sets
    let dataSet_ACTIVE  = BarChartDataSet(values: values_ACTIVE, label: "ACTIVE")
    let dataSet_REST    = BarChartDataSet(values: values_REST, label: "REST")

    //Set chart data
    let chartData = BarChartData()
    chartData.addDataSet(dataSet_REST)
    chartData.addDataSet(dataSet_ACTIVE)

    self.intervalBarChartView.data = chartData

    //  Bar sizes
    let barWidth = 1.0
    let barSpace = 0.10
    let groupSpace = 0.1

    chartData.groupBars(fromX: 0, groupSpace: groupSpace, barSpace: barSpace)
    chartData.barWidth = barWidth

    //  Bar Colors
    dataSet_ACTIVE.colors = [runOrange]
    dataSet_REST.colors = [RunGreen]
    self.intervalBarChartView.gridBackgroundColor = NSUIColor.white

    //  Enable/Disable show values and position of values
    chartData.setDrawValues(false)
    intervalBarChartView.drawValueAboveBarEnabled = false

    //  Bar Axes: 
    intervalBarChartView.xAxis.axisMinimum = 0.0
    intervalBarChartView.xAxis.axisMaximum = 10
    intervalBarChartView.leftAxis.axisMinimum = 0.0
    intervalBarChartView.rightAxis.enabled = false

    //  Bar Axes: GridLines
    self.intervalBarChartView.xAxis.drawGridLinesEnabled = false
    self.intervalBarChartView.xAxis.drawAxisLineEnabled = false

    self.intervalBarChartView.rightAxis.drawAxisLineEnabled = true
    self.intervalBarChartView.rightAxis.drawGridLinesEnabled = false

    self.intervalBarChartView.leftAxis.drawGridLinesEnabled = false
    self.intervalBarChartView.leftAxis.drawAxisLineEnabled = false

    //  Bar Text
    self.intervalBarChartView.chartDescription?.text = "Barchart Demo"

    //  Control interaction
    self.intervalBarChartView.doubleTapToZoomEnabled = false

}

EDIT

Here is what I get with two different compilations of settings :

With these settings :

    //  Bar sizes
    let barWidth = 0.3
    let barSpace = 0.10
    let groupSpace = 0.1

The gap between the bars is (more or less) equal:

enter image description here

However, with these setttings:

let groupSpace = 0.3
let barSpace = 0.05
let barWidth = 0.3

I get a wider gap between bars 2 and 3 (compared to 1 and 2)

enter image description here

kmn
  • 2,615
  • 4
  • 18
  • 28

1 Answers1

3

You need to change your barWidth calculation so that you can achieve what you expect in your output.

Logic of GroupBarChart Bar & Spacing calculation:

(baSpace + barWidth) * dataSet count + groupSpace = 1.0

So in your case you need to update above value like this:

let groupSpace = 0.3
let barSpace = 0.05
let barWidth = 0.3
// (0.3 + 0.05) * 2 + 0.3 = 1.00 -> interval per "group"

let startVal = 0

chartData.barWidth = barWidth;
chartData.groupBars(fromX: Double(startVal), groupSpace: groupSpace, barSpace: barSpace)

By doing this you will get proper cantered bar position in your bar chart.

Also one more option is only set BarWidth for your charts like below:

let barChartData = BarChartData(dataSet: barChartDataSet)
barChartData.barWidth = 0.4

Hope this will helps!

CodeChanger
  • 7,953
  • 5
  • 49
  • 80
  • Hey ! Thanks for answering. Unfortunately, it's only widened the difference between bars 2 and 3 (compared to 1 and 2) --- with these settings however, the gap is the same : ` // Bar sizes` `let barWidth = 0.3` `let barSpace = 0.10` `let groupSpace = 0.1` Unfortunately, could not add images to show you what I mean. It's true that the library isn't very documented. Any way of knowing what barSpacing and groupSpacing do that's different ? how do they influence calculations ? – kmn Mar 18 '19 at 18:38
  • can you add screen shot in ur question after setting above suggested values in your chart ? – CodeChanger Mar 19 '19 at 05:43
  • Done. Many Thanks ! – kmn Mar 19 '19 at 13:49
  • Hey ! I actually meant that I had uploaded the screenshots as you suggested. There's also the issue of the bar indesign : in `chartValueSelected`, I cannot easily retrieve the index of the bar in the set, rather, I only have the x value which is modified by setting bar widths and spaces. – kmn Mar 21 '19 at 16:33
  • 1
    So as per your screen shot its fine now you need to increase your bar width and decrease your bar & group spacing. – CodeChanger Mar 22 '19 at 10:14
  • so your new value looks like `barSpace = 0.05`,`barWidth=0.4` & `groupSpace=0.1` so in that case it will work. – CodeChanger Mar 22 '19 at 10:18
  • What I've ended up doing is : (1) setting integer values to all the bar x-values (2) ONLY setting bar widths to 0.3 with `let barWidth = 0.3; chartData.barWidth = barWidth`. This has done it : squat spacing, and each bar is referenced by the corresponding x value when selected – kmn Mar 26 '19 at 18:01
  • If you add this to your answer, I will be happy to mark it as an answer – kmn Mar 26 '19 at 18:01
  • sure let me edit my answer. and regarding X values its always in Integer or double so its basic requirement of charts library. – CodeChanger Mar 27 '19 at 05:49