【问题标题】:How to set different colour for each staked value of StackedBarChart如何为 StackedBarChart 的每个质押值设置不同的颜色
【发布时间】:2017-10-23 13:51:53
【问题描述】:

我正在使用 MPAndroidChart 库,我的要求是以堆栈颜色显示堆栈值,如图所示,也不在条形上方,而是左右交替堆栈。

我尝试过这种方式,但没有成功

          set.setValueTextColors(colorList);

它为一个完整的条提供一种颜色。

【问题讨论】:

    标签: android mpandroidchart


    【解决方案1】:

    我使用自定义渲染器来解决问题

    这里是代码

    图表创建

    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_mp_android_stacked_bar_chart);
            barChart = (BarChart) this.findViewById(R.id.bar_chart);
    
            float[] val1 = {10, 20, 30, 40, 50, 60, 70};
            float[] val2 = {70, 60, 50, 40, 30, 20, 10};
    
            ArrayList<BarEntry> yVals1 = new ArrayList<BarEntry>();
    
            for (int i = 0; i < val1.length; i++) {
                yVals1.add(new BarEntry(i, new float[]{val1[i], val2[i]}));
            }
    
            barChart.getDescription().setEnabled(false);
            barChart.setPinchZoom(false);      // scaling can now only be done on x- and y-axis separately
            barChart.setDrawGridBackground(false);
            barChart.setDrawBarShadow(false);
            barChart.setDrawValueAboveBar(true);
            barChart.setHighlightFullBarEnabled(false);
            barChart.getAxisRight().setEnabled(false);
    
            YAxis yAxis = barChart.getAxisLeft();       // change the position of the y-labels
            yAxis.setAxisMinimum(0f);
            yAxis.setDrawGridLines(false);
    
            XAxis xAxis = barChart.getXAxis();
            xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
            xAxis.setGranularity(1f);
            xAxis.setDrawGridLines(false);
    
            ArrayList<Integer> colorList = new ArrayList<>();
            colorList.add(ContextCompat.getColor(this, R.color.colorPrimaryDark));
            colorList.add(ContextCompat.getColor(this, R.color.colorAccent));
    
            barChart.getLegend().setEnabled(false);
            barChart.setRenderer(new StackedBarChartRenderer(barChart, barChart.getAnimator(), barChart.getViewPortHandler(), colorList));
    
    
    
            BarDataSet set1 = new BarDataSet(yVals1, "");
            set1.setColors(colorList);
            ArrayList<IBarDataSet> dataSets = new ArrayList<>();
    
    
    
            dataSets.add(set1);
            BarData data = new BarData(dataSets);
            barChart.setData(data);
            barChart.setVisibleXRangeMaximum(4f);
            barChart.invalidate();
        }
    

    这些是上述代码中的重要行。在这里,我们为传递所需颜色列表的图形设置自己的渲染器类

        ArrayList<Integer> colorList = new ArrayList<>();
        colorList.add(ContextCompat.getColor(this, R.color.colorPrimaryDark));
        colorList.add(ContextCompat.getColor(this, R.color.colorAccent));
        barChart.setRenderer(new StackedBarChartRenderer(barChart, barChart.getAnimator(), barChart.getViewPortHandler(), colorList));
    

    渲染器

    public class StackedBarChartRenderer extends BarChartRenderer {
    
        private ArrayList<Integer> colorList;
        private int index = 0;
        private int numOfColors;
    
        public StackedBarChartRenderer(BarDataProvider chart, ChartAnimator animator, ViewPortHandler viewPortHandler, ArrayList<Integer> colorList) {
            super(chart, animator, viewPortHandler);
            this.colorList = colorList;
            this.numOfColors = colorList.size();
        }
    
            public void drawValue(Canvas c, IValueFormatter formatter, float value, Entry entry, int dataSetIndex, float x, float y, int color) {
                mValuePaint.setColor(colorList.get(index));
                if(value != 0){
                c.drawText(formatter.getFormattedValue(value, entry, dataSetIndex, mViewPortHandler), x, y, mValuePaint);
               }
                index = ((index + 1) % (numOfColors));
            }
        }
    

    在上面的代码中,我们重写了必要的方法并以循环方式遍历 colorList。您可能需要更改逻辑 的 drawValue() 函数以满足您的要求。

    要了解有关自定义渲染器如何工作的更多信息,请查看此link

    结果

    编辑

    @Override
        public void drawValues(Canvas c) {
    
            // if values are drawn
            if (isDrawingValuesAllowed(mChart)) {
    
                List<IBarDataSet> dataSets = mChart.getBarData().getDataSets();
    
                final float valueOffsetPlus = Utils.convertDpToPixel(4.5f);
                float posOffset = 0f;
                float negOffset = 0f;
                boolean drawValueAboveBar = mChart.isDrawValueAboveBarEnabled();
    
                for (int i = 0; i < mChart.getBarData().getDataSetCount(); i++) {
    
                    IBarDataSet dataSet = dataSets.get(i);
    
                    if (!shouldDrawValues(dataSet))
                        continue;
    
                    // apply the text-styling defined by the DataSet
                    applyValueTextStyle(dataSet);
    
                    boolean isInverted = mChart.isInverted(dataSet.getAxisDependency());
    
                    // calculate the correct offset depending on the draw position of
                    // the value
                    float valueTextHeight = Utils.calcTextHeight(mValuePaint, "8");
                    posOffset = (drawValueAboveBar ? -valueOffsetPlus : valueTextHeight + valueOffsetPlus);
                    negOffset = (drawValueAboveBar ? valueTextHeight + valueOffsetPlus : -valueOffsetPlus);
    
                    if (isInverted) {
                        posOffset = -posOffset - valueTextHeight;
                        negOffset = -negOffset - valueTextHeight;
                    }
    
                    // get the buffer
                    BarBuffer buffer = mBarBuffers[i];
    
                    final float phaseY = mAnimator.getPhaseY();
    
                    MPPointF iconsOffset = MPPointF.getInstance(dataSet.getIconsOffset());
                    iconsOffset.x = Utils.convertDpToPixel(iconsOffset.x);
                    iconsOffset.y = Utils.convertDpToPixel(iconsOffset.y);
    
                    // if only single values are drawn (sum)
                    if (!dataSet.isStacked()) {
    
                        for (int j = 0; j < buffer.buffer.length * mAnimator.getPhaseX(); j += 4) {
    
                            float x = (buffer.buffer[j] + buffer.buffer[j + 2]) / 2f;
    
                            if (!mViewPortHandler.isInBoundsRight(x))
                                break;
    
                            if (!mViewPortHandler.isInBoundsY(buffer.buffer[j + 1])
                                    || !mViewPortHandler.isInBoundsLeft(x))
                                continue;
    
                            BarEntry entry = dataSet.getEntryForIndex(j / 4);
                            float val = entry.getY();
    
                            if (dataSet.isDrawValuesEnabled()) {
                                drawValue(c, dataSet.getValueFormatter(), val, entry, i, x,
                                        val >= 0 ?
                                                (buffer.buffer[j + 1] + posOffset) :
                                                (buffer.buffer[j + 3] + negOffset),
                                        dataSet.getValueTextColor(j / 4));
                            }
    
                            if (entry.getIcon() != null && dataSet.isDrawIconsEnabled()) {
    
                                Drawable icon = entry.getIcon();
    
                                float px = x;
                                float py = val >= 0 ?
                                        (buffer.buffer[j + 1] + posOffset) :
                                        (buffer.buffer[j + 3] + negOffset);
    
                                px += iconsOffset.x;
                                py += iconsOffset.y;
    
                                Utils.drawImage(
                                        c,
                                        icon,
                                        (int)px,
                                        (int)py,
                                        icon.getIntrinsicWidth(),
                                        icon.getIntrinsicHeight());
                            }
                        }
    
                        // if we have stacks
                    } else {
    
                        Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());
    
                        int bufferIndex = 0;
                        int index = 0;
    
                        while (index < dataSet.getEntryCount() * mAnimator.getPhaseX()) {
    
                            BarEntry entry = dataSet.getEntryForIndex(index);
    
                            float[] vals = entry.getYVals();
                            float x = (buffer.buffer[bufferIndex] + buffer.buffer[bufferIndex + 2]) / 2f;
    
                            int color = dataSet.getValueTextColor(index);
    
                            // we still draw stacked bars, but there is one
                            // non-stacked
                            // in between
                            if (vals == null) {
    
                                if (!mViewPortHandler.isInBoundsRight(x))
                                    break;
    
                                if (!mViewPortHandler.isInBoundsY(buffer.buffer[bufferIndex + 1])
                                        || !mViewPortHandler.isInBoundsLeft(x))
                                    continue;
    
                                if (dataSet.isDrawValuesEnabled()) {
                                    drawValue(c, dataSet.getValueFormatter(), entry.getY(), entry, i, x,
                                            buffer.buffer[bufferIndex + 1] +
                                                    (entry.getY() >= 0 ? posOffset : negOffset),
                                            color);
                                }
    
                                if (entry.getIcon() != null && dataSet.isDrawIconsEnabled()) {
    
                                    Drawable icon = entry.getIcon();
    
                                    float px = x;
                                    float py = buffer.buffer[bufferIndex + 1] +
                                            (entry.getY() >= 0 ? posOffset : negOffset);
    
                                    px += iconsOffset.x;
                                    py += iconsOffset.y;
    
                                    Utils.drawImage(
                                            c,
                                            icon,
                                            (int)px,
                                            (int)py,
                                            icon.getIntrinsicWidth(),
                                            icon.getIntrinsicHeight());
                                }
    
                                // draw stack values
                            } else {
    
                                float[] transformed = new float[vals.length * 2];
    
                                float posY = 0f;
                                float negY = -entry.getNegativeSum();
    
                                for (int k = 0, idx = 0; k < transformed.length; k += 2, idx++) {
    
                                    float value = vals[idx];
                                    float y;
    
                                    if (value == 0.0f && (posY == 0.0f || negY == 0.0f)) {
                                        // Take care of the situation of a 0.0 value, which overlaps a non-zero bar
                                        y = value;
                                    } else if (value >= 0.0f) {
                                        posY += value;
                                        y = posY;
                                    } else {
                                        y = negY;
                                        negY -= value;
                                    }
    
                                    transformed[k + 1] = y * phaseY;
                                }
    
                                trans.pointValuesToPixel(transformed);
    
                                for (int k = 0; k < transformed.length; k += 2) {
    
                                    final float val = vals[k / 2];
                                    final boolean drawBelow =
                                            (val == 0.0f && negY == 0.0f && posY > 0.0f) ||
                                                    val < 0.0f;
                                    float y = transformed[k + 1]
                                            + (drawBelow ? negOffset : posOffset);
    
                                    if (!mViewPortHandler.isInBoundsRight(x))
                                        break;
    
                                    if(val == 0){
                                        drawValue(c,
                                                dataSet.getValueFormatter(),
                                                vals[k / 2],
                                                entry,
                                                i,
                                                x,
                                                y,
                                                color);
                                    }
    
                                    if (!mViewPortHandler.isInBoundsY(y)
                                            || !mViewPortHandler.isInBoundsLeft(x))
                                        continue;
    
                                    if (dataSet.isDrawValuesEnabled()) {
                                        drawValue(c,
                                                dataSet.getValueFormatter(),
                                                vals[k / 2],
                                                entry,
                                                i,
                                                x,
                                                y,
                                                color);
                                    }
    
                                    if (entry.getIcon() != null && dataSet.isDrawIconsEnabled()) {
    
                                        Drawable icon = entry.getIcon();
    
                                        Utils.drawImage(
                                                c,
                                                icon,
                                                (int)(x + iconsOffset.x),
                                                (int)(y + iconsOffset.y),
                                                icon.getIntrinsicWidth(),
                                                icon.getIntrinsicHeight());
                                    }
                                }
                            }
    
                            bufferIndex = vals == null ? bufferIndex + 4 : bufferIndex + 4 * vals.length;
                            index++;
                        }
                    }
    
                    MPPointF.recycleInstance(iconsOffset);
                }
            }
        }
    

    将此函数添加到您的自定义渲染中,即使您的某些值在堆叠图中为 0,也可以选择正确的颜色。上述函数与以下部分的默认实现完全相同:

                               if(val == 0){
                                        drawValue(c,
                                                dataSet.getValueFormatter(),
                                                vals[k / 2],
                                                entry,
                                                i,
                                                x,
                                                y,
                                                color);
                                   }
    

    【讨论】:

    • 这个答案是正确的,应该被授予赏金
    • @amarok 如果所有堆栈值都大于 0 并且堆栈高度足以呈现值但在其他情况下不会为该值选择正确的颜色,则它的工作原理。它的发生是因为我们依赖于错误的索引值。我认为在这种情况下,所有堆栈都不会调用这个绘制值。你能告诉我如何解决这个问题。谢谢
    • 我正在测试这个数据 float[][] values = {{1, 20, 30,8}, {5, 0, 15,56}, {0, 3, 50,15 },{30, 20, 50,56}};
    • @PawanGupta 我已经更新了答案。可能会出现其他几个用例。您可以随时编辑渲染类以满足要求
    • @amarok 非常感谢!!你节省了一天。
    猜你喜欢
    • 2020-07-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-08
    • 1970-01-01
    • 2015-07-12
    • 1970-01-01
    • 2017-04-17
    • 1970-01-01
    相关资源
    最近更新 更多