Search code examples
iosobjective-cchartsios-charts

iOS: Two Bar Charts together


I am using charts library (Charts)

I am developing the application allows me to show number of guests in restaurant realtime and compare data between different days. For example look at this picture enter image description here

The dashed line means data for the compared to date. I would like to create BarChart like this but library only allows me to show 4 grouped bars. I want to show dashed bars above colored with small offset. Help me out please

enter image description here

My code is:

for (int i = 0; i < days.count; i++) {
        BarChartDataEntry *guysEntry = [[BarChartDataEntry alloc] initWithX:i y:[guys[i] integerValue]];
        [guysChartDataArray addObject:guysEntry];

        BarChartDataEntry *girlsEntry = [[BarChartDataEntry alloc] initWithX:i y:[girls[i] integerValue]];
        [girlsChartDataArray addObject:girlsEntry];

        BarChartDataEntry *guysCompareToEntry = [[BarChartDataEntry alloc] initWithX:i y:[guysCompareTo[i] integerValue]];
        [guysCompareToChartDataArray addObject:guysCompareToEntry];

        BarChartDataEntry *girlsCompareToEntry = [[BarChartDataEntry alloc] initWithX:i y:[girlsCompareTo[i] integerValue]];
        [girlsCompareToChartDataArray addObject:girlsCompareToEntry];
    }
    BarChartDataSet *guysChartDataSet = [[BarChartDataSet alloc] initWithValues:guysChartDataArray label:@"Guys"];
    guysChartDataSet.colors = @[[UIColor maleColor]];
    guysChartDataSet.valueTextColor = [UIColor clearColor];

    BarChartDataSet *girlsChartDataSet = [[BarChartDataSet alloc] initWithValues:girlsChartDataArray label:@"Girls"];
    girlsChartDataSet.colors = @[[UIColor femaleColor]];
    girlsChartDataSet.valueTextColor = [UIColor clearColor];

    LineChartXAxisFormatter *barGraphXFormatter = [[LineChartXAxisFormatter alloc] init];
    barGraphXFormatter.xLabels = [days mutableCopy];
    self.barChartView.xAxis.valueFormatter = barGraphXFormatter;
    self.barChartView.xAxis.centerAxisLabelsEnabled = YES;

    self.combinedChartView.xAxis.valueFormatter = barGraphXFormatter;
    self.combinedChartView.xAxis.centerAxisLabelsEnabled = YES;

    float groupSpace = 0.06f;
    float barSpace = 0.02f;
    float barWidth = 0.45f;

    BarChartDataSet *guysCompareToChartDataSet = [[BarChartDataSet alloc] initWithValues:guysCompareToChartDataArray label:@"Guys (Compare)"];
    guysCompareToChartDataSet.colors = @[[UIColor clearColor]];
    guysCompareToChartDataSet.barBorderWidth = 1.f;
    guysCompareToChartDataSet.barBorderColor = [UIColor grayColor];
    guysCompareToChartDataSet.isDashedBorder = YES;

    guysCompareToChartDataSet.axisDependency = AxisDependencyLeft;
    guysCompareToChartDataSet.valueTextColor = [UIColor clearColor];

    BarChartDataSet *girlsCompareToChartDataSet = [[BarChartDataSet alloc] initWithValues:girlsCompareToChartDataArray label:@"Girls (Compare)"];
    girlsCompareToChartDataSet.colors = @[[UIColor clearColor]];
    girlsCompareToChartDataSet.barBorderWidth = 1.f;
    girlsCompareToChartDataSet.barBorderColor = [UIColor grayColor];
    girlsCompareToChartDataSet.isDashedBorder = YES;
    girlsCompareToChartDataSet.axisDependency = AxisDependencyLeft;
    girlsCompareToChartDataSet.valueTextColor = [UIColor clearColor];

    NSArray *dataSets = @[guysChartDataSet, girlsChartDataSet, guysCompareToChartDataSet, girlsCompareToChartDataSet];

    BarChartData *barChartData = [[BarChartData alloc] initWithDataSets:dataSets];
    barChartData.barWidth = barWidth;

    CGFloat initialValue = 0;
    CGFloat groupCount = days.count;

    self.barChartView.xAxis.axisMinimum = initialValue;

    self.barChartView.xAxis.axisMaximum = initialValue + [barChartData groupWidthWithGroupSpace:groupSpace barSpace: barSpace] * groupCount;

    [barChartData groupBarsFromX:0 groupSpace:groupSpace barSpace:barSpace];
    self.barChartView.data = barChartData;

I want to make something like: enter image description here


Solution

  • Now that you've changed your question, this requires a different solution.

    As I mentioned in the comments before, you need to manually calculate each bar's position. Then, don't use the grouping feature, because you've already grouped them how you want.

    // Determine bar sizing and spacing parameters.
    int barsPerGroup = 2;
    double targetGroupWidth = 1;
    double barSpacing = 0.2;
    double groupSpacing = 0.3;
    double barWidth = (targetGroupWidth - groupSpacing - barSpacing * barsPerGroup) / barsPerGroup;
    double compareBarOffset = barWidth / 3;
    
    for (int i = 0; i < entryCount; i++) {
    
        // Determine X position for each bar
        // NOTE: This is the most important step!
        double groupStartPosition = targetGroupWidth * i;
    
        double group1X = groupStartPosition + barWidth / 2;
        double group1CompareX = group1X + compareBarOffset;
    
        double group2X = group1X + barWidth + barSpacing;
        double group2CompareX = group2X + compareBarOffset;
    
    
        // Create data entries positioned at values calculated by previous step
        NSNumber *group1Value = group1[i];
        NSNumber *group1CompareValue = group1Compare[i];
    
        NSNumber *group2Value = group2[i];
        NSNumber *group2CompareValue = group2Compare[i];
    
    
        BarChartDataEntry *group1DataEntry = [[BarChartDataEntry alloc] initWithX:group1X
                                                                                y:[group1Value doubleValue]];
        BarChartDataEntry *group1CompareDataEntry = [[BarChartDataEntry alloc] initWithX:group1CompareX
                                                                                       y:[group1CompareValue doubleValue]];
    
        BarChartDataEntry *group2DataEntry = [[BarChartDataEntry alloc] initWithX:group2X
                                                                                y:[group2Value doubleValue]];
        BarChartDataEntry *group2CompareEntry = [[BarChartDataEntry alloc] initWithX:group2CompareX
                                                                                   y:[group2CompareValue doubleValue]];
    
    
        // ...
    }
    
    // Create Data Sets, set styles, etc.
    // ...
    
    // Do NOT use this method because bars are already grouped.
    //[barChartView groupBarsFromX:0 groupSpace:groupSpacing barSpace:barSpacing];
    

    RESULT:

    Note: I can't find the property isDashedBorder, so I don't know what version of the library you're using. Instead, I just set clear bars with a solid gray border.

    Chart with orange and blue bars with overlapping bars for comparison