Anudeep
Anudeep

Reputation: 1570

MpAndroidChart set background between limit lines

I a using MpAndroidChart library. I need to implement a design where I need to color the area between two limit lines. I have attached an image for reference. I have tried multiple ways but I have failed to achieve it. I am using this library for the first time. Can anyone help me about how this could be achieved. As you can see the green shade behind the line graph. Which is the limit. I need to get that green shade

As you can see the green shade behind the line graph. Which is the limit. I need to get that green shade

Thanks in advance,

Anudeep Reddy.

Upvotes: 3

Views: 6112

Answers (4)

JUehV
JUehV

Reputation: 63

As this is still an issue I throw in my two cents. I tried the solution of @HouseOfHufflepuff but I got the error message that I use too much limit lines in the plot. It seems to work anyway but I guess the performance is not optimal.

So I implemented a subclass for drawing zones in the background. Maybe it's helpful for someone:

public class TargetZoneCombinedChart extends CombinedChart {

    protected Paint mYAxisSafeZonePaint;
    private List<TargetZone> mTargetZones;

    public TargetZoneCombinedChart(Context context) {
        super(context);
    }

    public TargetZoneCombinedChart(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public TargetZoneCombinedChart(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void init() {
        super.init();
        mYAxisSafeZonePaint = new Paint();
        mYAxisSafeZonePaint.setStyle(Paint.Style.FILL);
        // mGridBackgroundPaint.setColor(Color.rgb(240, 240, 240));
        mTargetZones = new ArrayList<>();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        for (TargetZone targetZone : mTargetZones) {
            // prepare coordinates
            float[] pts = new float[4];
            pts[1] = targetZone.lowerLimit;
            pts[3] = targetZone.upperLimit;
            mLeftAxisTransformer.pointValuesToPixel(pts);

            // draw
            mYAxisSafeZonePaint.setColor(targetZone.color);
            canvas.drawRect(mViewPortHandler.contentLeft(), pts[1], mViewPortHandler.contentRight(),
                    pts[3], mYAxisSafeZonePaint);
        }
        super.onDraw(canvas);
    }

    public void addTargetZone(TargetZone targetZone){
        mTargetZones.add(targetZone);
    }

    public List<TargetZone> getTargetZones(){
        return mTargetZones;
    }

    public void clearTargetZones(){
        mTargetZones = new ArrayList<>();
    }

    public static class TargetZone {
        public final int color;
        public final float lowerLimit;
        public final float upperLimit;

        public TargetZone(int color, float lowerLimit, float upperLimit) {
            this.color = color;
            this.lowerLimit = lowerLimit;
            this.upperLimit = upperLimit;
        }
    }
}

To add a zone you just need to add a target zone object:

float rangeHigh = 180f;
float rangeLow = 80f;

chart.addTargetZone(new TargetZoneCombinedChart.TargetZone(                Color.parseColor("#33b5eb45"),rangeLow,rangeHigh));

whereby the ranges are y values of the left axis.

Upvotes: 4

HouseOfHufflepuff
HouseOfHufflepuff

Reputation: 51

I had the same problem but reached a different workaround without having to subclass the LineChart. Using canvas to draw the rectangle works, but you have to translate your charts coordinates to the canvas coordinates. You cannot use a single limit line as there is a limit to the width of the line. The workaround I used was to simply loop through limit lines to create a rectangle within my range.

    float increment = (rangeHigh - rangeLow) / 20;
    float metricLine = rangeLow;

    for(int i = 0; i < 20; i++) {
        LimitLine llRange = new LimitLine(metricLine, "");
        llRange.setLineColor(Color.parseColor("#b5eb45"));
        llRange.setLineWidth(10f);
        leftAxis.addLimitLine(llRange);
        metricLine = metricLine + increment;
    }

graph

Upvotes: 3

PaulT
PaulT

Reputation: 4296

This can be done by sub-classing the chart class (e.g. LineChart) and then overriding the onDraw() method. In the overridden onDraw() you can draw the rectangle(s) you need directly onto the canvas and then call super.onDraw() to complete the rendering of the chart.

There is an example of how to do this on the MP Android Github (see below). I followed the code in the example and it worked well for me.

https://github.com/PhilJay/MPAndroidChart/issues/485

Upvotes: 2

Harsh Pandey
Harsh Pandey

Reputation: 831

I don't think that there is a direct way to achieve this, but this workaround should help you:

LimitLine ll = new LimitLine(lowerLimit, "Systolic range");
ll.setLineColor(Color.GREEN);
ll.setLineWidth(upperLimit - lowerLimit);

ll.setTextColor(Color.WHITE);
ll.setTextSize(12f);

chart.getAxisLeft().setDrawLimitLinesBehindData(true);

The important thing here is the method setDrawLimitLinesBehindData(true).

As always, all the information is available in the documentation.

Upvotes: 3

Related Questions