Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to set multiple StackBar ? #1801

Closed
PreechaS opened this issue Nov 8, 2016 · 10 comments
Closed

How to set multiple StackBar ? #1801

PreechaS opened this issue Nov 8, 2016 · 10 comments

Comments

@PreechaS
Copy link

PreechaS commented Nov 8, 2016

I have 2 StackBar, each one likes this :

simulator screen shot nov 8 2559 be 5 50 38 pm
let barData = BarChartData(dataSets: [attemptDataSet])

simulator screen shot nov 8 2559 be 5 52 10 pm
let barData = BarChartData(dataSets: [resultDataSet])

This is what I get when trying to put them together into the same chart :
simulator screen shot nov 8 2559 be 5 49 02 pm
let barData = BarChartData(dataSets: [attemptDataSet, resultDataSet])

And this is the result I got with swift 2
chart iphone6

I don't know how to make it work as before with swift 3.

@liuxuan30
Copy link
Member

liuxuan30 commented Nov 9, 2016

It's nothing about swift. Because you add it in a wrong way. You array should have only 1 data set and the stacked data has size of 3. Take a look at ChartDemo.

@PreechaS
Copy link
Author

PreechaS commented Nov 9, 2016

Sorry, I can't figure out how to fix this.
I think I did what you said and It used to work well with the previous version of iOS-charts.

I try to simplify my code so you may can tell me what is wrong.

    for i in 0..<12 {
        let value = Double(i)
        let attempt = BarChartDataEntry(x: value, y: value)
        attemptEntries.append(attempt)
        let result = BarChartDataEntry(x: value, yValues: [2*value, 3*value])
        resultEntries.append(result)
    }
    let attemptDataSet = BarChartDataSet(values: attemptEntries, label: Constants.Chart.TotalAttempt.Label)
    let resultDataSet = BarChartDataSet(values: resultEntries, label: Constants.Chart.Result.Label)

    let dataSets = [attemptDataSet, resultDataSet]
    let barData = BarChartData(dataSets: dataSets)

    chartView.data = barData

simulator screen shot nov 9 2559 be 3 02 09 pm

@liuxuan30
Copy link
Member

liuxuan30 commented Nov 11, 2016

sorry, I misunderstand your q. Just too many sceenshots to get clear. You want to show 1 normal bar and 1 stacked bar together?

If so, I think you missed one line:
[data groupBarsFromX: startYear groupSpace: groupSpace barSpace: barSpace];
Please take a look at ChartsDemo - multiple bar chart. And release notes!

Take below code into multiple bar chart to replace, works like a charm:

- (void)setDataCount:(int)count range:(double)range
{
    float groupSpace = 0.08f;
    float barSpace = 0.03f;
    float barWidth = 0.2f;
    // (0.2 + 0.03) * 4 + 0.08 = 1.00 -> interval per "group"

    NSMutableArray *yVals1 = [[NSMutableArray alloc] init];
    NSMutableArray *yVals2 = [[NSMutableArray alloc] init];
    NSMutableArray *yVals3 = [[NSMutableArray alloc] init];
    NSMutableArray *yVals4 = [[NSMutableArray alloc] init];

    double randomMultiplier = range * 100000.f;

    int groupCount = count + 1;
    int startYear = 1980;
    int endYear = startYear + groupCount;

    for (int i = startYear; i < endYear; i++)
    {
        [yVals1 addObject:[[BarChartDataEntry alloc]
                           initWithX:i
                           y:(double) (arc4random_uniform(randomMultiplier))]];

        [yVals2 addObject:[[BarChartDataEntry alloc]
                           initWithX:i
                           y:(double) (arc4random_uniform(randomMultiplier))]];

        [yVals3 addObject:[[BarChartDataEntry alloc]
                           initWithX:i
                           y:(double) (arc4random_uniform(randomMultiplier))]];

        [yVals4 addObject:[[BarChartDataEntry alloc] initWithX:i yValues:@[@((arc4random_uniform(randomMultiplier))), @((arc4random_uniform(randomMultiplier))), @((arc4random_uniform(randomMultiplier)))]]];
    }

    BarChartDataSet *set1 = nil, *set2 = nil, *set3 = nil, *set4 = nil;
    if (_chartView.data.dataSetCount > 0)
    {
        set1 = (BarChartDataSet *)_chartView.data.dataSets[0];
        set2 = (BarChartDataSet *)_chartView.data.dataSets[1];
        set3 = (BarChartDataSet *)_chartView.data.dataSets[2];
        set4 = (BarChartDataSet *)_chartView.data.dataSets[3];
        set1.values = yVals1;
        set2.values = yVals2;
        set3.values = yVals3;
        set4.values = yVals4;

        BarChartData *data = _chartView.barData;

        _chartView.xAxis.axisMinimum = startYear;
        _chartView.xAxis.axisMaximum = [data groupWidthWithGroupSpace:groupSpace barSpace: barSpace] * _sliderX.value + startYear;
        [data groupBarsFromX: startYear groupSpace: groupSpace barSpace: barSpace];

        [_chartView.data notifyDataChanged];
        [_chartView notifyDataSetChanged];
    }
    else
    {
        set1 = [[BarChartDataSet alloc] initWithValues:yVals1 label:@"Company A"];
        [set1 setColor:[UIColor colorWithRed:104/255.f green:241/255.f blue:175/255.f alpha:1.f]];

        set2 = [[BarChartDataSet alloc] initWithValues:yVals2 label:@"Company B"];
        [set2 setColor:[UIColor colorWithRed:164/255.f green:228/255.f blue:251/255.f alpha:1.f]];

        set3 = [[BarChartDataSet alloc] initWithValues:yVals3 label:@"Company C"];
        [set3 setColor:[UIColor colorWithRed:242/255.f green:247/255.f blue:158/255.f alpha:1.f]];

        set4 = [[BarChartDataSet alloc] initWithValues:yVals4 label:@"Company D"];
        set4.colors = @[ChartColorTemplates.material[0], ChartColorTemplates.material[1], ChartColorTemplates.material[2]];

        NSMutableArray *dataSets = [[NSMutableArray alloc] init];
        [dataSets addObject:set1];
        [dataSets addObject:set2];
        [dataSets addObject:set3];
        [dataSets addObject:set4];

        BarChartData *data = [[BarChartData alloc] initWithDataSets:dataSets];
        [data setValueFont:[UIFont fontWithName:@"HelveticaNeue-Light" size:10.f]];
        [data setValueFormatter:[[LargeValueFormatter alloc] init]];

        // specify the width each bar should have
        data.barWidth = barWidth;

        // restrict the x-axis range
        _chartView.xAxis.axisMinimum = startYear;

        // groupWidthWithGroupSpace(...) is a helper that calculates the width each group needs based on the provided parameters
        _chartView.xAxis.axisMaximum = startYear + [data groupWidthWithGroupSpace:groupSpace barSpace: barSpace] * groupCount;

        [data groupBarsFromX: startYear groupSpace: groupSpace barSpace: barSpace];

        _chartView.data = data;
    }
}

@PreechaS
Copy link
Author

Thanks for your advice.
Now I can show multiple Stackbars on my chart but the problem of xAxis Label alignment #1334 still exists and every other xAxis Label will not show. I set labelCount to force it show all then all labels appear but still not align with the groupBars.

Are there any methods to calculate the barWidth, barSpace, and groupWidth which their values make groupBars size equal to xAxis Label spacing ?

    attemptEntries = [BarChartDataEntry]()
    resultEntries = [BarChartDataEntry]()
    for i in 1...12 {
        let value = Double(i)
        let attempt = BarChartDataEntry(x: value, y: value)
        attemptEntries.append(attempt)
        let result = BarChartDataEntry(x: value, yValues: [2*value, 3*value])
        resultEntries.append(result)
    }

    let barData = BarChartData(dataSets: [resultDataSet, attemptDataSet])
    barData.barWidth = 0.35
    barData.groupBars(fromX: 1, groupSpace: 0.2, barSpace: 0.02)
    barData.notifyDataChanged()

    chartView.xAxis.centerAxisLabelsEnabled = true
    chartView.xAxis.axisMinimum = 1
    chartView.xAxis.axisMaximum  = 13
    chartView.xAxis.labelCount = 12

simulator screen shot nov 11 2559 be 1 36 50 pm

@liuxuan30
Copy link
Member

liuxuan30 commented Nov 15, 2016

werid.. Have you tried ChartsDemo? I don't see it. Your code can't say anything. But what you could try is, put view.data = barData at last.
I saw

chartView.xAxis.centerAxisLabelsEnabled = true
    chartView.xAxis.axisMinimum = 1
    chartView.xAxis.axisMaximum  = 13
    chartView.xAxis.labelCount = 12

But I didn't see where you call view.data = barData.

I changed ChartDemo to be horizontal (don't mind the labels overlap and legend, I did cheat), it's fine:
mhb
So do take your time to check out ChartDemo first.

@PreechaS
Copy link
Author

After a long day, I finally found the cause of "xAxis label not align with its values". The group size (barWidth + barSpace)_no of bars + groupSpace must be equal to 1 ,otherwise bars will not align with their label. In my case, the size = (0.35+0.02)_2+0.2 is not equal to 1 so, the bars are not align with labels.

I can prove by modify MultiBarChart to HorizontalBarChart (as you did). It can show 1 StackedBar with 3 normal Bars correctly because its group size is 1.
simulator screen shot nov 15 2559 be 9 06 36 pm

Then, I just remove 2 datasets and leave the others things (barWidth, barSpace..) the same. Due to missing 2 datasets, group size now is smaller than 1 so xAxis will not align anymore.
simulator screen shot nov 15 2559 be 9 07 27 pm

@PreechaS
Copy link
Author

Below is my code after remove 2 datasets. You may use it to verify that whether or not my understanding and conclusion is correct.

- (void)setDataCount:(int)count range:(double)range
{
    float groupSpace = 0.08f;
    float barSpace = 0.03f;
    float barWidth = 0.2f;
    // (0.2 + 0.03) * 4 + 0.08 = 1.00 -> interval per "group"

    NSMutableArray *yVals1 = [[NSMutableArray alloc] init];
    NSMutableArray *yVals2 = [[NSMutableArray alloc] init];
    NSMutableArray *yVals3 = [[NSMutableArray alloc] init];
    NSMutableArray *yVals4 = [[NSMutableArray alloc] init];

    double randomMultiplier = range * 100000.f;

    int groupCount = count + 1;
//    int groupCount = 12;
    int startYear = 1980;
    int endYear = startYear + groupCount;

    for (int i = startYear; i < endYear; i++)
    {
        double val1 = (double) (arc4random_uniform(randomMultiplier) / 3);
        double val2 = (double) (arc4random_uniform(randomMultiplier) / 3);
        double val3 = (double) (arc4random_uniform(randomMultiplier) / 3);

        [yVals1 addObject:[[BarChartDataEntry alloc] initWithX:i yValues:@[@(val1), @(val2), @(val3)]]];

        [yVals2 addObject:[[BarChartDataEntry alloc]
                           initWithX:i
                           y:(double) (arc4random_uniform(randomMultiplier))]];

        [yVals3 addObject:[[BarChartDataEntry alloc]
                           initWithX:i
                           y:(double) (arc4random_uniform(randomMultiplier))]];

        [yVals4 addObject:[[BarChartDataEntry alloc]
                           initWithX:i
                           y:(double) (arc4random_uniform(randomMultiplier))]];
    }

    BarChartDataSet *set1 = nil, *set2 = nil, *set3 = nil, *set4 = nil;
    if (_chartView.data.dataSetCount > 0)
    {

        set1 = (BarChartDataSet *)_chartView.data.dataSets[0];
        set2 = (BarChartDataSet *)_chartView.data.dataSets[1];
        set3 = (BarChartDataSet *)_chartView.data.dataSets[2];
        set4 = (BarChartDataSet *)_chartView.data.dataSets[3];
        set1.values = yVals1;
        set2.values = yVals2;
        set3.values = yVals3;
        set4.values = yVals4;

        BarChartData *data = _chartView.barData;

        _chartView.xAxis.axisMinimum = startYear;
        _chartView.xAxis.axisMaximum = [data groupWidthWithGroupSpace:groupSpace barSpace: barSpace] * _sliderX.value + startYear;
        [data groupBarsFromX: startYear groupSpace: groupSpace barSpace: barSpace];

        [_chartView.data notifyDataChanged];
        [_chartView notifyDataSetChanged];
    }
    else
    {
        set1 = [[BarChartDataSet alloc] initWithValues:yVals1 label:@"Company A"];
//        [set1 setColor:[UIColor colorWithRed:104/255.f green:241/255.f blue:175/255.f alpha:1.f]];
        set1.colors = @[[UIColor colorWithRed:255/255.f green:0/255.f blue:0/255.f alpha:1.f], [UIColor colorWithRed:0/255.f green:255/255.f blue:0/255.f alpha:1.f], [UIColor colorWithRed:0/255.f green:0/255.f blue:255/255.f alpha:1.f]];
        set2 = [[BarChartDataSet alloc] initWithValues:yVals2 label:@"Company B"];
        [set2 setColor:[UIColor colorWithRed:164/255.f green:228/255.f blue:251/255.f alpha:1.f]];

        set3 = [[BarChartDataSet alloc] initWithValues:yVals3 label:@"Company C"];
        [set3 setColor:[UIColor colorWithRed:242/255.f green:247/255.f blue:158/255.f alpha:1.f]];

        set4 = [[BarChartDataSet alloc] initWithValues:yVals4 label:@"Company D"];
        [set4 setColor:[UIColor colorWithRed:255/255.f green:102/255.f blue:0/255.f alpha:1.f]];

        NSMutableArray *dataSets = [[NSMutableArray alloc] init];
        [dataSets addObject:set1];
        [dataSets addObject:set2];
//        [dataSets addObject:set3];
//        [dataSets addObject:set4];

        BarChartData *data = [[BarChartData alloc] initWithDataSets:dataSets];
        [data setValueFont:[UIFont fontWithName:@"HelveticaNeue-Light" size:10.f]];
        [data setValueFormatter:[[LargeValueFormatter alloc] init]];

        // specify the width each bar should have
        data.barWidth = barWidth;

        // restrict the x-axis range
        _chartView.xAxis.axisMinimum = startYear;

        // groupWidthWithGroupSpace(...) is a helper that calculates the width each group needs based on the provided parameters
        _chartView.xAxis.axisMaximum = startYear + [data groupWidthWithGroupSpace:groupSpace barSpace: barSpace] * groupCount;

        [data groupBarsFromX: startYear groupSpace: groupSpace barSpace: barSpace];

        _chartView.data = data;
    }
}

@liuxuan30
Copy link
Member

hmm, you may want to summerize if it's too long. Problem solved, right?

@PreechaS
Copy link
Author

PreechaS commented Nov 17, 2016

Yes.

Summary is already on the top.

After a long day, I finally found the cause of "xAxis label not align with its values". The group size (barWidth + barSpace)no of bars + groupSpace must be equal to 1, otherwise bars will not align with their label. In my case, the size = (0.35+0.02)2+0.2 is not equal to 1 so, the bars are not align with labels.

The later is samples supporting my conclusion.
It might look quite long but actually just a big screen capture. (I've already tried to scale down the images but it's detail too small to see then difficult to understand)

The next comment is code modified from ChartDemo and used to show samples which you may want to verify and confirm before sharing to other developers.

@MrAngrez
Copy link

hello, please help me i have only one array for the stack bar values and i have to create stack bar chart using it. but i'm not geeing proper so help me please. hear is my code.

print(arrValue)
for l in 0..<arrValue.count
{
let dataEntry = BarChartDataEntry(x: Double(count), y:arrValue[l] as! Double, data: nil)
print(dataEntry)
dataEntries.append(dataEntry)
}
count += 1
print(dataEntries)

        chartDataSet = BarChartDataSet(values: dataEntries, label: "")
    }

multiple values in arrValue. and i have to set that values in same index that's why i put count += 1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants