The axes Chapter 2 of 35

The settings that both axes share: which parts are drawn, how many labels there are, how the value range is chosen, and the lines you can put on top.

AxisBase is the base class of XAxis and YAxis. Everything on this page works on either one.

val xAxis = chart.xAxis
val leftAxis = chart.axisLeft
val rightAxis = chart.axisRight

What an axis is made of#

An axis can draw four things, each of which can be turned off on its own.

  • The labels, one per computed axis value.
  • The axis line, drawn along the edge of the content area, parallel to the labels.
  • The grid lines, one running across the content area from each label.
  • The limit lines you add yourself, for a target or a threshold.
PropertyMeaningDefault
isEnabledDraws the axis at all. False hides every part of it, whatever the other settings say.true
isDrawLabelsEnabledDraws the labels. Grid and axis line are unaffected.true
isDrawAxisLineEnabledDraws the line along the axis.true
isDrawGridLinesEnabledDraws the grid lines.true
chart.xAxis.isDrawGridLinesEnabled = false
chart.axisRight.isEnabled = false

How many labels#

labelCount is a wish, not a promise. The renderer picks a round interval near range / labelCount, so you usually get a count close to what you asked for, with readable values.

PropertyMeaningDefault
labelCountNumber of labels you want, clamped to axisMinLabels..axisMaxLabels.6
isForceLabelsEnabledDraws exactly labelCount labels, evenly spread.false
axisMinLabelsLower bound applied to labelCount.2
axisMaxLabelsUpper bound applied to labelCount.25

Forcing the count gives you an exact number of labels at the price of uneven values, which is what you want when you fixed the range yourself:

chart.axisLeft.axisMinimum = 30f
chart.axisLeft.axisMaximum = 110f
chart.axisLeft.labelCount = 5
chart.axisLeft.isForceLabelsEnabled = true
The old setLabelCount(count, force) is gone. labelCount and isForceLabelsEnabled are two independent properties now, and you can change either one without touching the other.

Granularity#

Granularity is the smallest interval the axis is allowed to use. Without it, zooming in keeps halving the interval until the same label appears twice, for example three labels reading "4" because the real values are 4.0, 4.3 and 4.6 and the axis formats whole numbers.

chart.xAxis.granularity = 1f

Assigning granularity also sets isGranularityEnabled to true, so one line is enough. The property starts at 1, but the feature is off until you enable it. You can also enable it on its own with isGranularityEnabled = true to use the default interval of 1.

The value range#

By default both ends of the range are computed from the data whenever the data changes. Assign either end to fix it.

chart.axisLeft.axisMinimum = 0f     // always start at zero
chart.axisLeft.axisMaximum = 100f

An assignment marks that end custom: isAxisMinCustom and isAxisMaxCustom read true, and the value survives every later recalculation. To hand an end back to the chart, call resetAxisMinimum() or resetAxisMaximum(). The change takes effect the next time the range is computed, which is the next notifyDataSetChanged() or the next assignment of chart.data.

spaceMin and spaceMax pad a computed end in value space. They are ignored for an end you fixed yourself.

chart.xAxis.spaceMin = 0.5f   // half a slot before the first entry
chart.xAxis.spaceMax = 0.5f

BarChart, ScatterChart and CandleStickChart already set both to 0.5 on their x axis, which is what keeps the outer bars and points off the edge.

spaceMin and spaceMax only work on the x axis. The y axis computes its range differently and uses spaceTop and spaceBottom, which are percentages. See the y axis.

axisRange is the distance between the two ends and is updated whenever either end changes.

Text#

The label text settings come from ComponentBase and are shared with the legend and the description.

PropertyMeaningDefault
textSizeLabel size in dp, clamped to 6..24.10
textColorLabel color.black
typefaceTypeface for the labels, or null for the default.null
xOffsetHorizontal space in dp between the labels and what they sit next to.5
yOffsetVertical space in dp between the labels and what they sit next to.4 on the x axis, 0 on the y axis
chart.axisLeft.apply {
    textSize = 11f
    textColor = Color.parseColor("#8A93A6")
    typeface = ResourcesCompat.getFont(context, R.font.inter)
}

Grid lines and the axis line#

Both are plain lines with a color, a width in dp and an optional dash pattern.

PropertyMeaningDefault
gridColorColor of the grid lines.gray
gridLineWidthGrid line width in dp.0.5
axisLineColorColor of the axis line.gray
axisLineWidthAxis line width in dp.0.5
isDrawGridLinesBehindDataEnabledDraws the grid behind the data instead of on top of it.true
chart.axisLeft.apply {
    gridColor = Color.parseColor("#1F2A3C")
    gridLineWidth = 1f
    isDrawAxisLineEnabled = false
    enableGridDashedLine(10f, 10f, 0f)
}

enableGridDashedLine(lineLength, spaceLength, phase) takes pixels: the length of a dash, the gap after it, and where in the pattern to start (pass 0). disableGridDashedLine() goes back to a solid line and isGridDashedLineEnabled tells you which one is active. The axis line has the same three functions under enableAxisLineDashedLine, disableAxisLineDashedLine and isAxisLineDashedLineEnabled.

Limit lines#

A LimitLine is a line at a fixed value with an optional label. On a y axis it runs horizontally, on an x axis vertically. Use it for a target, a threshold or an average.

val limit = LimitLine(140f, "Critical").apply {
    lineWidth = 2f
    lineColor = Color.RED
    textSize = 11f
    labelPosition = LimitLine.LimitLabelPosition.RIGHT_TOP
    enableDashedLine(10f, 10f, 0f)
}

chart.axisLeft.addLimitLine(limit)
PropertyMeaningDefault
limitThe value the line sits at. Set in the constructor.
labelText next to the line. An empty string draws no label.""
lineWidthLine width in dp, clamped to 0.2..12.1
lineColorLine color.light red
labelPositionCorner the label is drawn at.RIGHT_TOP
textStylePaint style of the label text.FILL_AND_STROKE
isEnabledDraws this line. False skips it without removing it.true

The four label positions are LEFT_TOP, LEFT_BOTTOM, RIGHT_TOP and RIGHT_BOTTOM. For a horizontal line on a y axis, left and right pick the end of the line and top and bottom pick the side of it. For a vertical line on an x axis it is the other way around: left and right pick the side, top and bottom pick the end. The radar chart draws limit lines on its y axis only, and never draws their labels.

limitLines is the list of lines on the axis, in the order they were added. removeLimitLine(line) takes one out and removeAllLimitLines() clears them. Adding more than six logs a warning, because past that point they stop being readable.

By default limit lines are drawn on top of the data. Put them behind it with:

chart.axisLeft.isDrawLimitLinesBehindDataEnabled = true

Formatting the labels#

valueFormatter turns an axis value into label text. Set any IAxisValueFormatter, which is a fun interface, so a lambda works:

chart.axisLeft.valueFormatter = IAxisValueFormatter { value, _ -> "${value.toInt()} €" }

Until you set one, the axis returns a DefaultAxisValueFormatter built from the computed decimals. Formatting values covers the built in formatters and how to write your own.

Values the axis computes#

The axis renderer fills these on every draw pass, from the visible range. You can read them, but not assign them.

PropertyMeaning
entriesThe values labels and grid lines are drawn at. The array is only ever grown, so read the first entryCount of them.
entryCountHow many of them there are.
centeredEntriesThe midpoints between neighbouring entries, used when labels are centered.
decimalsDecimal digits the default formatter uses, derived from the label interval.
longestLabelThe formatted label with the most characters.

They are empty until the chart has data and has been laid out, so reading them from onCreate gives you nothing. getFormattedLabel(index) returns the text of one entry, or an empty string for an index outside the range.

Next#