iOS:两个条形图在一起

iOS: Two Bar Charts together

我正在使用图表库 (Charts)

我正在开发的应用程序允许我实时显示餐厅的客人数量并比较不同日期之间的数据。 例如看这张照片

虚线表示比较日期的数据。我想像这样创建条形图,但库只允许我显示 4 个分组的条形图。我想在带有小偏移量的彩色上方显示虚线条。请帮帮我

我的代码是:

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;

我想制作类似这样的东西:

有了Charts,看来你可以:

  1. 将数据堆叠到同一个柱中。
  2. 对条形进行分组,使它们重叠。

看起来你也不能:

  1. 为堆叠条形图中的每个数据条目指定单独的边框颜色。 (如果您提供边框颜色,它将应用于整个栏。)

关于文档的注意事项

请记住 ChartsMPAndroidChart 为蓝本并非常接近 API。

因此,如果您需要帮助,请参考他们的documentation。 Java 语法对我来说有点陌生,但是在 Xcode 的自动完成的帮助下,我能够找到我需要的一切。

代码:

请注意三个具体部分:

  1. 如何创建堆叠数据条目。
  2. 无法为堆叠栏中的每个项目设置单独的边框。
  3. 如何通过提供负条间距来重叠条。

我绝不是这个库的专家,但只要阅读文档,我就能把它们放在一起。

// MARK: Data Entries

for (int i = 0; i < days.count; i++) {
    NSNumber *guyValue = guys[i];
    NSNumber *girlValue = girls[i];


    // NOTE 1: To get "stacked" bars, use the initializer `initWithX:yValues:`
    BarChartDataEntry *guyGirlDataEntry = [[BarChartDataEntry alloc] initWithX:i
                                                                       yValues:@[guyValue, girlValue]];


    NSNumber *guyCompareToValue = guysCompareTo[i];
    NSNumber *girlCompareToValue = girlsCompareTo[i];

    BarChartDataEntry *guyGirlCompareToEntry = [[BarChartDataEntry alloc] initWithX:i
                                                                            yValues:@[guyCompareToValue, girlCompareToValue]];

    [guyGirlChartDataArray addObject:guyGirlDataEntry];
    [guyGirlCompareToChartDataArray addObject:guyGirlCompareToEntry];
}



// MARK: Data Sets

BarChartDataSet *guysGirlsChartDataSet = [[BarChartDataSet alloc] initWithValues:guyGirlChartDataArray label:nil];
BarChartDataSet *guysGirlsCompareToChartDataSet = [[BarChartDataSet alloc] initWithValues:guyGirlCompareToChartDataArray label:nil];

BarChartData *data = [[BarChartData alloc] initWithDataSets:@[guysGirlsCompareToChartDataSet, guysGirlsChartDataSet]];



// MARK: Styling

guysGirlsChartDataSet.stackLabels = @[@"Guys", @"Girls"];
guysGirlsChartDataSet.colors = @[[UIColor maleColor],
                                 [UIColor femaleColor]];

// NOTE 2: Unfortunately, you can only set one border color to the bar.
// It seems, you won't be able to use separate dashed borders in the same bar, like you want.
// For demonstration purposes, I've simply made the comparison colors 50% transparent.
guysGirlsCompareToChartDataSet.stackLabels = @[@"Guys (Compare)", @"Girls (Compare)"];
guysGirlsCompareToChartDataSet.colors = @[[[UIColor maleColor] colorWithAlphaComponent:0.5],
                                          [[UIColor femaleColor] colorWithAlphaComponent:0.5]];

// Sets the x axis label interval, so it doesn't show labels like "0.9"
barChartView.xAxis.granularity = 1;

// Centers the x axis label over the bar group, rather than on the grid line.
barChartView.xAxis.centerAxisLabelsEnabled = YES;



// MARK: Displaying Chart Data

barChartView.data = data;

// Grouping

// I still can't seem to set this properly.
// Even though I tell it to fit the bars exactly and don't show below 0 on the x axis,
// the chart still shows below zero and the right-most bar gets cut off.

// If this isn't a bug, then perhaps you can find the answer to this elsewhere.
barChartView.fitBars = YES;
[barChartView setVisibleXRangeMinimum:0];

// Calculate bar grouping parameters.
NSInteger barCountPerGroup = data.dataSetCount;
double barWidth = 0.4;

// NOTE 3: Negative bar spacing will make the bars overlap.
double barSpace = -0.3;

// According to documentation, total group width (bars and spacing) must add up to 1
double groupSpace = 1 - (barWidth + barSpace) * barCountPerGroup;

// Set the grouping parameters.
data.barWidth = barWidth;
[barChartView groupBarsFromX:0 groupSpace:groupSpace barSpace:barSpace];

// Refresh the chart (if necessary)
[barChartView notifyDataSetChanged];

输出:

样式不是很好,但条形按您想要的方式分组和重叠。

我相信您可以在别处找到有关样式的帮助。

现在您已经更改了问题,这需要不同的解决方案。

正如我之前在评论中提到的,您需要手动计算每个柱的位置。然后,不要使用分组功能,因为您已经按照自己的意愿对它们进行了分组。

// 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];

结果:

注意:我找不到 属性 isDashedBorder,所以我不知道你使用的是什么版本的库。相反,我只是设置了带有纯灰色边框的清晰条。