Pie Chart Entries Outside Slices Have Different Position Offsets

How do I find an appropriate position for my labels on a pie chart?

I think the problem is that NSAttriutedString.draw always draws the text from the top left corner

Sure, the draw method will place origin of the string right in the point you pass. In this case solution is simple - find the size of string and make correct origin.

let size = attributedString.size()
let origin = CGPoint(x: textX - size.width / 2, y: textY - size.height / 2)
attributedString.draw(at: origin)

Result:

Sample Image

How to offset biggest slice automaticly in google pie chart?

Utilizing the API, you can use the getSortedRows() method.

data.getSortedRows([{column: 1, desc: true}]) will return the sorted array of row IDs. index 0 will be the largest one. Then it's a simple matter of applying that to your options variable:

google.charts.load("current", {packages:["corechart"]});google.charts.setOnLoadCallback(drawChart);function drawChart() {  var data = google.visualization.arrayToDataTable([    ['Language', 'Speakers (in millions)'],    ['Assamese', 13], ['Bengali', 83], ['Bodo', 1.4],    ['Dogri', 2.3], ['Gujarati', 46], ['Hindi', 300],    ['Kannada', 38], ['Kashmiri', 5.5], ['Konkani', 5],    ['Maithili', 20], ['Malayalam', 33], ['Manipuri', 1.5],    ['Marathi', 72], ['Nepali', 2.9], ['Oriya', 33],    ['Punjabi', 29], ['Sanskrit', 0.01], ['Santhali', 6.5],    ['Sindhi', 2.5], ['Tamil', 61], ['Telugu', 74], ['Urdu', 52]  ]);
var options = { title: 'Indian Language Use', legend: 'none', pieSliceText: 'label', slices: {} }; options.slices[data.getSortedRows([{column: 1, desc: true}])[0]] = {offset: 0.1};
var chart = new google.visualization.PieChart(document.getElementById('piechart')); chart.draw(data, options);}
<script src="https://www.gstatic.com/charts/loader.js"></script><div id="piechart" style="width: 500px; height: 400px;"></div>

MPAndroid chart pie label getting cut off

I am facing same issue. I solved this using below line of code.

piecPieChart.setExtraBottomOffset(20f); 
piecPieChart.setExtraLeftOffset(20f);
piecPieChart.setExtraRightOffset(20f);

Hope It will help someone.

Pie Chart Alignment issue using MPAndroidChart

You could use outside values in order to keep clear your dataset names for small pieces of data.

For example, you could achieve something like that:

Outside values

Here is the code. This code is supposed to use when overriding a PieChart. If you are not overriding it, you should adapt this code to work with your PieChart directly, such as mChart.setData(); instead of setData();.

PieDataSet dataSet = new PieDataSet(entries, null);
dataSet.setSliceSpace(3f);
dataSet.setIconsOffset(new MPPointF(0, 40));
dataSet.setSelectionShift(5f);

// Outside values
dataSet.setXValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
dataSet.setYValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
dataSet.setValueLinePart1OffsetPercentage(100f); /** When valuePosition is OutsideSlice, indicates offset as percentage out of the slice size */
dataSet.setValueLinePart1Length(0.6f); /** When valuePosition is OutsideSlice, indicates length of first half of the line */
dataSet.setValueLinePart2Length(0.6f); /** When valuePosition is OutsideSlice, indicates length of second half of the line */
setExtraOffsets(0.f, 5.f, 0.f, 5.f); // Ofsets of the view chart to prevent outside values being cropped /** Sets extra offsets (around the chart view) to be appended to the auto-calculated offsets.*/

PieData data = new PieData(dataSet);
data.setValueTextSize(10f);
data.setValueTextColor(Color.BLACK);
setData(data);

MPAndroidChart PieChart label on top of the value

You can define a custom CustomPieChartRenderer which is a subclass of PieChartRenderer and override the below two methods we are interested to:

override fun drawEntryLabel(c: Canvas?, label: String, x: Float, y: Float)
override fun drawValue(c: Canvas?, valueText: String, x: Float, y: Float, color: Int)

The drawEntryLabel function is called when an entry label is ready to be drawn on Canvas at the specified x, y position.

The drawValue function is called when a value is ready to be drawn on Canvas at the specified x, y position.

Each of the above superclass functions draws a Text on Canvas using a Paint like c.drawText(label, x, y, mEntryLabelsPaint) or c.drawText(valueText, x, y, mValuePaint). When a label-value pair is ready to be drawn the above functions are called sequentially. So in the CustomPieChartRenderer when each function is called instead of calling superclass to draw the Text we save each data (value/label) temporary and we draw them when we have both label/value x, y positions. To align the label on top of the value we need only to swap the labelY position with valueY position during the drawing phase of each Text.

Below is the CustomPieChartRenderer:

class CustomPieChartRenderer(chart: PieChart?, animator: ChartAnimator?, viewPortHandler: ViewPortHandler?) : PieChartRenderer(chart, animator, viewPortHandler) {

private var mHasLabelData = false
private var mHasValueData = false
private var mEntryLabelCanvas: Canvas? = null
private var mValueCanvas: Canvas? = null
private var mEntryLabel: String = ""
private var mValueText: String = ""
private var mEntryLabelX = 0f
private var mValueX = 0f
private var mEntryLabelY = 0f
private var mValueY = 0f
private var mValueColor = 0

override fun drawEntryLabel(c: Canvas?, label: String, x: Float, y: Float) {
//instead of calling super save the label data temporary
//super.drawEntryLabel(c, label, x, y)
mHasLabelData = true
//save all entry label information temporary
mEntryLabelCanvas = c
mEntryLabel = label
mEntryLabelX = x
mEntryLabelY = y
//and check if we have both label and value data temporary to draw them
checkToDrawLabelValue()
}

override fun drawValue(c: Canvas?, valueText: String, x: Float, y: Float, color: Int) {
//instead of calling super save the value data temporary
//super.drawValue(c, valueText, x, y, color)
mHasValueData = true
//save all value information temporary
mValueCanvas = c
mValueText = valueText
mValueX = x
mValueY = y
mValueColor = color
//and check if we have both label and value data temporary to draw them
checkToDrawLabelValue()
}

private fun checkToDrawLabelValue() {
if (mHasLabelData && mHasValueData) {
drawLabelAndValue()
mHasLabelData = false
mHasValueData = false
}
}

private fun drawLabelAndValue() {
//to show label on top of the value just swap the mEntryLabelY with mValueY
drawEntryLabelData(mEntryLabelCanvas, mEntryLabel, mEntryLabelX, mValueY)
drawValueData(mValueCanvas, mValueText, mValueX, mEntryLabelY, mValueColor)
}

//This is the same code used in super.drawEntryLabel(c, label, x, y) with any other customization you want in mEntryLabelsPaint
private fun drawEntryLabelData(c: Canvas?, label: String, x: Float, y: Float) {
val mEntryLabelsPaint: Paint = paintEntryLabels
mEntryLabelsPaint.setColor(Color.BLACK)
mEntryLabelsPaint.setTypeface(Typeface.DEFAULT_BOLD)
mEntryLabelsPaint.setTextAlign(Paint.Align.CENTER)
c?.drawText(label, x, y, mEntryLabelsPaint)
}

//This is the same code used in super.drawValue(c, valueText, x, y, color) with any other customization you want in mValuePaint
fun drawValueData(c: Canvas?, valueText: String, x: Float, y: Float, color: Int) {
mValuePaint.color = color
mValuePaint.textAlign = Paint.Align.CENTER
c?.drawText(valueText, x, y, mValuePaint)
}
}

And here is a sample usage:

class PieChartActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.piechart_layout)

val pieChart = findViewById<PieChart>(R.id.pieChart)

//initialize a List of colors one for each slice
val pieColors: ArrayList<Int> = ArrayList()
pieColors.add(Color.parseColor("#0f2c4b"))
pieColors.add(Color.parseColor("#1857a0"))
pieColors.add(Color.parseColor("#238837"))
pieColors.add(Color.parseColor("#3f9cff"))

//initialize a List of PieEntry with its value/label pair
val pieEntries: ArrayList<PieEntry> = ArrayList()
pieEntries.add(PieEntry(40f, "NA"))
pieEntries.add(PieEntry(18f, "MENA"))
pieEntries.add(PieEntry(20f, "EU"))
pieEntries.add(PieEntry(22f, "ASIA"))

//prepare the PieDataSet with the above pieEntries and pieColors
val pieDataSet = PieDataSet(pieEntries, "")
pieDataSet.valueTextSize = 14f
pieDataSet.colors = pieColors

//draw value/label outside the pie chart
pieDataSet.xValuePosition = PieDataSet.ValuePosition.OUTSIDE_SLICE
pieDataSet.yValuePosition = PieDataSet.ValuePosition.OUTSIDE_SLICE
pieDataSet.valueLinePart1OffsetPercentage = 100f
pieDataSet.valueLinePart1Length = 0.8f
pieDataSet.valueLinePart2Length = 0f
pieDataSet.valueTextColor = Color.BLACK
pieDataSet.valueTypeface = Typeface.DEFAULT_BOLD
pieDataSet.valueLineColor = ColorTemplate.COLOR_NONE

//prepare the PieData
val pieData = PieData(pieDataSet)
pieData.setValueTextColor(Color.BLACK)
pieData.setDrawValues(true)
pieData.setValueFormatter(PercentFormatter(pieChart))

//set pieChart data and any other pieChart property needed
pieChart.data = pieData
pieChart.setExtraOffsets(35f, 35f, 35f, 35f)
pieChart.setEntryLabelColor(Color.BLACK)
pieChart.setEntryLabelTextSize(14f)
pieChart.setEntryLabelTypeface(Typeface.DEFAULT_BOLD)
pieChart.setUsePercentValues(true)
pieChart.legend.isEnabled = false
pieChart.description.isEnabled = false
pieChart.isRotationEnabled = true
pieChart.dragDecelerationFrictionCoef = 0.9f
pieChart.rotationAngle = 220f
pieChart.isHighlightPerTapEnabled = true
pieChart.animateY(1400, Easing.EaseInOutQuad)
pieChart.setHoleColor(Color.WHITE)

//set the custom renderer (CustomPieChartRenderer) used to draw each label on top of the value and call invalidate to redraw the chart
pieChart.renderer = CustomPieChartRenderer(pieChart, pieChart.animator, pieChart.viewPortHandler)
pieChart.invalidate()
}
}

Piechart Xml Layout :

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">

<com.github.mikephil.charting.charts.PieChart
android:id="@+id/pieChart"
android:layout_width="match_parent"
android:layout_height="match_parent" />

</RelativeLayout>

Result:

piechart

Note: This is tested with 'com.github.PhilJay:MPAndroidChart:v3.1.0'



Related Topics



Leave a reply



Submit