26

I am trying to show X axis label to go to 2 lines when they are long. How to achieve this in LineChart? See screenshot below. I want time to go to second line instead of staying next to date

enter image description here

NinjaCoder
  • 2,381
  • 3
  • 24
  • 46

7 Answers7

41

For those like me who want to achieve this but keep the original library, here is a simple solution inspired by @fgueli's modifications. This applies for one break line only (add "\n" in your labels) but you can easily adapt it to your needs.

  1. Subclass XAxisRenderer

    public class CustomXAxisRenderer extends XAxisRenderer {
        public CustomXAxisRenderer(ViewPortHandler viewPortHandler, XAxis xAxis, Transformer trans) {
             super(viewPortHandler, xAxis, trans);
        }
    
        @Override
        protected void drawLabel(Canvas c, String formattedLabel, float x, float y, MPPointF anchor, float angleDegrees) {
            String line[] = formattedLabel.split("\n");
            Utils.drawXAxisValue(c, line[0], x, y, mAxisLabelPaint, anchor, angleDegrees);
            Utils.drawXAxisValue(c, line[1], x + mAxisLabelPaint.getTextSize(), y + mAxisLabelPaint.getTextSize(), mAxisLabelPaint, anchor, angleDegrees);
        }
    }
    

  1. Set this renderer on the desired chart

    lineChart.setXAxisRenderer(new CustomXAxisRenderer(lineChart.getViewPortHandler(), lineChart.getXAxis(), lineChart.getTransformer(YAxis.AxisDependency.LEFT)));
    

  1. Enjoy!

LineChart labels on multiple lines

  • Please include the plot in your answer and not a link, the link later can break and your answer will be incomplete – Ibo Oct 10 '17 at 22:43
  • 2
    @Ibo I am sorry but I can't: _You're not allowed to embed images in your posts yet, so we've included a link instead. As soon as you earn 10 reputation on the site, you'll be able to embed images._ – Guillaume Jounel Oct 10 '17 at 23:02
  • 2
    This solution is not working for HorizontalBarChart when setting LEFT YAxis to enable false for hiding it. And when using RIGHT YAxis for getting transformer it is giving `12-19 18:46:19.631 10003-10003/com.aegisisc.samplecharts A/libc: Fatal signal 11 (SIGSEGV) at 0x00000004 (code=1), thread 10003 (sc.samplecharts)` – Rajen Raiyarela Dec 19 '17 at 13:20
  • @GuillaumeJounel - Its not working for me. Just showing line[0] value, text after "\n" is not drawn. Can you Pls help me. – Rahul Parihar Mar 01 '18 at 20:40
  • How I can use this solution with the radarchart ? – blk0ut Apr 16 '18 at 13:23
  • 2
    @RahulParihar, just increase viewport offsets, so 2nd line can be seen, like so: chart.setViewPortOffsets(0, 0, 0, getResources().getDimensionPixelSize(R.dimen.radiobutton_size)); and radiobutton_size is 36dp in my case (with 8dp text size) – Roman T. Jul 21 '18 at 18:33
  • 8
    BTW, if one wants to get multiline text centered (so line[0] will be above line[0] centered), he shouldn't use `Utils.drawXAxisValue(c, line[1], x + mAxisLabelPaint.getTextSize(), y + mAxisLabelPaint.getTextSize(), mAxisLabelPaint, anchor, angleDegrees);` but instead `Utils.drawXAxisValue(c, line[1], x, y + mAxisLabelPaint.getTextSize(), mAxisLabelPaint, anchor, angleDegrees);` – Roman T. Jul 21 '18 at 18:40
  • Possible index out of bounds error? What about if there is only 1 line: `line[] = ... split("\n")` will be a 1 index array and `line[1]` will break? – JFreeman Feb 05 '19 at 07:39
  • Works nearly perfect. Both lines are slightly overlapping. How can I put more space between them? – Kaspatoo Feb 27 '19 at 12:40
  • --> got it: in drawXAxisValue(...) are x and y used to set the size. The thing is, that this is calculated from the original orientation of the label. So using rotation (-45) will make it overlap again. We need pythagoras here. – Kaspatoo Feb 27 '19 at 12:59
  • Or if you know it keeps -45 just use the original solution of this answer and do not change as suggested by comment of RomanT. (this all only in case of use of the improvement of answer of @Peter B. – Kaspatoo Feb 27 '19 at 13:03
  • This solution worked for me in a Vertical Bar Chart. In a Horizontal Bar Chart doesn't work. I noticed that the y value passed to the drawLabel method is always 28. and all the label are printed one on the other. Can you help me ? Maybe I have to change the transformer ? – Salvo Parisi Apr 03 '20 at 14:47
  • thank you both @GuillaumeJounel and RomanT. i am affraid about this stuf in many times. now it is solve. good answer. – Randika Wanninayaka Jan 21 '21 at 07:34
  • Can I drawable to text with this approach? – Rahul Pawar Feb 02 '21 at 10:06
19

I modified the library to allow multiline label on the xAxis using \n

https://github.com/fabriziogueli/MPAndroidChart/tree/axis_multiline_labels

It is working right now but need further testing and maybe some code styling / adjustment.

XAxis xAxis = mChart.getXAxis();
xAxis.setMultiLineLabel(true);

Then you can use for example a SimpleDateFormat like this:

SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yy\nHH:mm a");

Maybe you have to set extra bottom offset to your chart:

mChart.setExtraBottomOffset(50);
fgueli
  • 367
  • 4
  • 13
  • Can you maybe include some snippets from the classes that you used inside the answer? I am assuming you have to modify the renderer somehow and maybe the `Utils` class – David Rawson Feb 03 '17 at 21:51
  • 1
    Yes, i modified the XAxisRenderer and Utils classes. You can see the changes here: https://github.com/fabriziogueli/MPAndroidChart/commit/6c5f22bf3b1f359052618d51a76fbf8ee07e0444 – fgueli Feb 05 '17 at 15:53
  • 1
    This works well, hopefully it will get folded into the main project ASAP! Is there anyway to center the text? Right now, it is left justified, which looks odd. Thanks! – Bourne Feb 28 '17 at 15:00
  • 1
    @Bourne you are right, there was a problem with the alignment. I fixed it. Check the new version here: https://github.com/fabriziogueli/MPAndroidChart/tree/axis_multiline_labels. – fgueli Mar 04 '17 at 20:29
  • @fabriziogueli Awesome, that works nicely! I would just note for anyone wanting to use it, that the second line is still left justified with the first line, so it isn't line-per-line centered. That is probably going to take a more robust solution with multiple strings (arraylist maybe)? But the current alignment fix makes it a whole lot better and, for my purposes, I was able to make it look pretty good with just adding an extra space in the second line (i.e. I used "MMM d\n yyyy" instead of "MMM d\nyyyy"). – Bourne Mar 06 '17 at 14:39
  • Even thought using compile 'com.github.PhilJay:MPAndroidChart:v3.0.1', getting error on setMultiLineLabel() as cannot resolve. Will you pleaase help me out @fabriziogueli – Tara Apr 19 '17 at 12:25
  • @Tara yes because this feature is not present in the official library. If you want to use this version, you have to download it from here: https://github.com/fabriziogueli/MPAndroidChart/tree/axis_multiline_labels – fgueli Apr 21 '17 at 18:36
  • I did this, by creating a sample program from downloaded project and gave longer labels for x axis, but again result is same. – Tara Apr 24 '17 at 08:51
  • @Tara you have to set the correct valueFormatter on the XAxis object and use a SimpleDateFormat with '\n" – fgueli Jun 14 '17 at 14:27
  • mpandroidchart 3.1.0 has same issue it is not work setMultilielable. ould you fix it? – Randika Wanninayaka Jan 21 '21 at 06:39
8

Improved version of @Guillaume Jounel's answer to support multiple newlines, as well as strings w/o a newline.

@Override
protected void drawLabel(Canvas c, String formattedLabel, float x, float y,
                             MPPointF anchor, float angleDegrees) {
String line[] = formattedLabel.split("\n");
Utils.drawXAxisValue(c, line[0], x, y, mAxisLabelPaint, anchor, angleDegrees);
    for (int i = 1; i < line.length; i++) { // we've already processed 1st line
         Utils.drawXAxisValue(c, line[i], x, y + mAxisLabelPaint.getTextSize() * i,
             mAxisLabelPaint, anchor, angleDegrees);
    }
}
David Buck
  • 3,752
  • 35
  • 31
  • 35
Peter
  • 328
  • 3
  • 7
  • 1
    This works great, but I needed to add extra space below the chart like so: `chart.setExtraOffsets(0.toFloat(), 0.toFloat(), 0.toFloat(), xLabelExtraHeight)` – Mike76 Oct 31 '19 at 08:58
  • Can I add drawable to text with this approach? – Rahul Pawar Feb 02 '21 at 10:12
7

This looks like something that you will have to implement yourself by modifying the library to your needs.

It is currently not possible by default to have multiple lines on the x-axis. The reason therefore is that Android Canvas cannot simply plot a string e.g. like this "Line 1\nLine2" as two lines.

Philipp Jahoda
  • 50,880
  • 24
  • 180
  • 187
4

No need to offset x coordinate. And for multi-line scenario the code should be

@Override
protected void drawLabel(Canvas c, String formattedLabel, float x, float y, MPPointF anchor, float angleDegrees) {
    String lines[] = formattedLabel.split("\n");
    for (int i = 0; i < lines.length; i++) {
        float vOffset = i * mAxisLabelPaint.getTextSize();
        Utils.drawXAxisValue(c, lines[i], x, y + vOffset, mAxisLabelPaint, anchor, angleDegrees);
    }
}
Eugene Shtoka
  • 1,117
  • 1
  • 8
  • 14
2

Use the @Guillaume Jounel answer and then add:

XAxis xAxis = lineChart.getXAxis();    
xAxis.setLabelRotationAngle(-30f);
2

In Horizontal Barchart below solved the problem.

class CustomXAxisRenderer(viewPortHandler: ViewPortHandler?, xAxis: XAxis?, trans: Transformer?, chart: HorizontalBarChart) : XAxisRendererHorizontalBarChart(viewPortHandler, xAxis, trans, chart) {
    override fun drawLabel(c: Canvas?, formattedLabel: String, x: Float, y: Float, anchor: MPPointF?, angleDegrees: Float) {
        val line: List<String> = formattedLabel.split("\n")
        Utils.drawXAxisValue(c, line[0], x, y, mAxisLabelPaint, anchor, angleDegrees)
        for (i in 1 until line.size) {
            Utils.drawXAxisValue(c, line[i], x, y + mAxisLabelPaint.textSize * i,
                mAxisLabelPaint, anchor, angleDegrees)
        }
    }
}

and called as follows

barChart.setXAxisRenderer(CustomXAxisRenderer(barChart.viewPortHandler, xAxis, barChart.getTransformer(yAxis.axisDependency), barChart))
David Buck
  • 3,752
  • 35
  • 31
  • 35
dharani
  • 53
  • 7