Android MPAndroidCharts LineChart skipping values - android

I´m working with MPAndroid charts on my app to draw a chart from my sqlite database using "weight" values for the Y axes and "date" values for the X axes.
The problem is that just some rows of my database have that weight value. When all the rows have the weight layout my code works like a charm, but when there is a row that doesn´t have weight value, and the next one contains that weight value, it leaves a space on the YAxes of the chart, altought the date value is set on XAxes. As a result of that, a value is missed on Y Axes for every row without the weight value, because the value that comes after the weight row is moved one point forward. For example:
I have this code for setting up the chart:
public void setUpCharts(){
chart = (LineChart) rootView.findViewById(R.id.weightChart);
chart.setNoDataTextDescription("Nothing");
chart.setDrawBorders(false);
chart.setDescription("");
chart.getXAxis().setPosition(XAxis.XAxisPosition.BOTTOM);
chart.getAxisRight().setEnabled(false);
chart.getAxisLeft().setEnabled(false);
chart.getAxisLeft().setDrawGridLines(false);
chart.getAxisRight().setDrawGridLines(false);
chart.getXAxis().setDrawGridLines(false);
chart.getXAxis().setDrawAxisLine(false);
chart.getLegend().setEnabled(false);
chart.setScaleEnabled(false);
chart.setPinchZoom(false);
chart.setDoubleTapToZoomEnabled(false);
weights = new ArrayList<>(); //Pesos
dates = new ArrayList<String>(); //Días del mes
getChartData();
LineDataSet dataSet = new LineDataSet(weights, "Weights");
dataSet.setDrawCubic(false);
dataSet.setCircleRadius(4);
dataSet.setLineWidth(3);
dataSet.setDrawValues(true);
dataSet.setColor(getContext().getResources().getColor(R.color.colorWeightChart));
dataSet.setCircleColor(getContext().getResources().getColor(R.color.colorWeightChart));
dataSet.setCircleColorHole(getContext().getResources().getColor(R.color.colorWeightChart));
LineData data = new LineData(dates, dataSet);
chart.setData(data);
//LimitLine
String weight_get = PreferenceManager.getDefaultSharedPreferences(getContext()).getString("Goal_weight", null);
if(!weight_get.equals(null) && !weight_get.equals("")){
float weight_goal = Float.valueOf(weight_get);
YAxis leftAxis = chart.getAxisLeft();
LimitLine ll = new LimitLine(weight_goal);
ll.setLineColor(getContext().getResources().getColor(R.color.weightTabFAB));
ll.setLineWidth(1f);
ll.enableDashedLine(10f, 10f, 0f);
leftAxis.addLimitLine(ll);
float YMax= dataSet.getYMax();
if(weight_goal > YMax){
float difference = weight_goal - YMax;
chart.getAxisRight().setAxisMaxValue(weight_goal + difference); //So the limit line will be always visible
chart.getAxisLeft().setAxisMaxValue(weight_goal + difference);
}
}
chart.setVisibleXRangeMaximum(5f);
}
And I use getChartData to set up all the chart data getting the values from my sqlite database. It´s supposed to add just the values of rows in which weight exists, and in fact the log shows that it works correctly, so I don´t know how can I fix it.
protected void getChartData(){
IDs = new ArrayList<Integer>();
Cursor data = dataSource.getAllItems();
if(data!=null) {
while(data.moveToNext()){
int id = data.getInt(data.getColumnIndex(RecordsDataSource.ColumnRecords.ID_RECORDS));
String weight= data.getString(data.getColumnIndex(RecordsDataSource.ColumnRecords.WEIGHTS_RECORDS));
if(weight!=null && !weight.equals("")){
long milisDate =data.getLong(data.getColumnIndex(RecordsDataSource.ColumnRecords.DATES_RECORDS));
String date = Utils.milisToDate(milisDate, "dd/MM");
IDs.add(id);
weights.add(new Entry(Float.valueOf(weight), id -1));
dates.add(date);
Log.i("ID "+ String.valueOf(id),"Not null, "+ weight);
}else{
Log.i("ID "+ String.valueOf(id), "Null");
}
}
data.close();
}
}
I have been all the day trying to solve this issue, but nothing has worked.
Could somebody help me please?
By the way, sorry for my bad English.

The problem is in your id in getChartData() method. The id is skipping your chart Entry position.
Instead of this
weights.add(new Entry(Float.valueOf(weight), -1));
Add a variable for entry index and increment it on each iteration
index++;
weights.add(new Entry(Float.valueOf(weight), index));
It should work.

Related

BarChart with MPAndroidChart : bars are invisible

I am using MPAndroidChart to generate a simple bar chart, inside a collapsing toolbar. When I add entries, the value of the entry is visible at the correct height on the chart, but I can't see the bar.
This is how I create my variables:
final List<BarEntry> barEntries = new ArrayList<>();
final BarDataSet barDataSet = new BarDataSet(barEntries, getResources().getString(R.string.cycles_profiled));
final BarData barData = new BarData(barDataSet);
This is how I populate the data and refresh the chart:
final Calendar cal = getFirstDayOfWeek();
for (int i = 0; i < NUMBER_OF_DAYS; i++) {
long date = cal.getTimeInMillis();
barEntries.add(new BarEntry(date, map.get(date)));
cal.add(Calendar.DAY_OF_WEEK, 1);
}
barDataSet.setValues(barEntries);
barChart.setData(barData);
barData.notifyDataChanged();
barChart.notifyDataSetChanged();
barChart.invalidate();
I have no problem creating bar charts in other parts of my app. When I draw linecharts inside the collapsing toolbar, it also works fine.
Had the same issue, solved it thanks to OumaSyuu.
For some reason the BarChart has a difficulty with milliseconds.. convert your milliseconds to minutes: TimeUnit.MILLISECONDS.toMinutes(millisecondValue) and your life will be honey!
If converting to minutes doesn't help try to a different (higher) time unit. The time unit that will be good for you is the average gap between the bars, for me it was hours.
Another interesting point that may help you style the chart - In the method setBarWidth(float mBarWidth), the input mBarWidth represent values not pixels.
i was facing the same issue when i used timestamp for X axis values which was reported as a bug in the library, so i came out with the following solution
first create an arraylist:
ArrayList<String> xAxis_stringArray = new ArrayList<>();
and then while you add the entries to the entry list, set the x value to be the index of the data source (string value) and add the string value to the string array like that:
jsonObject = results.getJSONObject(index);
String s = jsonObject.getString(x);
xAxis_stringArray.add(s);
entries.add(new Entry(Float.valueOf(index), Float.valueOf(jsonObject.getString(y))));
and finally refer the xAxis to the value formatter class:
XAxis xAxis = sum_chart.getXAxis();
xAxis.setValueFormatter(new TimeAxisValueFormatter(xAxis_stringArray));
TimeAxisValueFormatter class:
public class TimeAxisValueFormatter implements IAxisValueFormatter {
ArrayList<String> arrayList = new ArrayList<>();
public TimeAxisValueFormatter(ArrayList<String> list) {
this.arrayList = list;
}
#Override
public String getFormattedValue(float value, AxisBase axis) {
return arrayList.get(Math.round(value));
}}
You are missing to set .setColor
Try with
barDataSet.setColor(Color.rgb(0, 155, 0)); //Put your RGB Color
I had the same problem just now, for me increasing the barwidth solved the problem. I think the problem lays with how spread out your data is which impacts the width of the lines. If you have a dataset that is only spread out over an hour and has entry for every minute of that hour, I think this problem won't exist. But if you are like me and have sparse data over 5 hours or so, then the barwidth just become smaller and smaller to accommodate all those entries and the bar just disappears.
Example:
data.setBarWidth(2f);
When I increased the barwidth to 80f:
data.setBarWidth(80f);

MPAndroidChart vertical values

I want to delimit on vertical values between 13 and 14 not this is how it looks my linear chart, always starts on 0 as the starting limit, I want to be something around 13. Please see the image on the next link to see what I am talking about, I am attaching the piece of code for it enter image description here
LineChart lineChart = (LineChart) rootView.findViewById(R.id.chart);
LineData data = new LineData(labels, dataset);
dataset.setColors(ColorTemplate.COLORFUL_COLORS); //
dataset.setDrawCubic(true);
dataset.setDrawFilled(true);
lineChart.setData(data);
lineChart.animateY(5000);
Finally I got the answer about this, you can check it here
LineChart lineChart = (LineChart) rootView.findViewById(R.id.chart);
LineData data = new LineData(labels, dataset);
lineChart.getAxisLeft().setLabelCount(2, true);
lineChart.getAxisRight().setEnabled(false);
lineChart.getAxisLeft().setStartAtZero(false);
lineChart.setAutoScaleMinMaxEnabled(false);
lineChart.getAxisLeft().setAxisMaxValue(maxYval + 1);
lineChart.getAxisLeft().setAxisMinValue(minYval - 1);
dataset.setColors(ColorTemplate.COLORFUL_COLORS); //
dataset.setValueTextSize(10);
dataset.setDrawCubic(true);
dataset.setDrawFilled(true);
lineChart.setData(data);
lineChart.animateY(10);

How to setDrawCircles() for only one (maximum) value in the chart?

I am using mpandroidchart and I want to draw a circle only for one Entry in the LineDataSet but not the rest. I have tried to accomplish it using two LineDataSets but it hasn't worked so far. Here's my code:
LineDataSet scoreDataSet = new LineDataSet(values, "Score");
scoreDataSet.setDrawCircles(false);
// Entry with max value is the last one
Entry circleEntry = scoreDataSet.getEntryForXIndex(scoreDataSet.getEntryCount()-1);
LineDataSet circularDataSet = new LineDataSet(values, "Score");
circularDataSet.setDrawCircles(true);
int size = circularDataSet.getEntryCount()-1;
for (int i=0; i<size; i++) {
if (i != circleEntry.getXIndex()) {
circularDataSet.removeEntry(circularDataSet.getEntryForXIndex(i));
}
}
.
.
.
ArrayList<LineDataSet> dataSets = new ArrayList<LineDataSet>();
dataSets.add(scoreDataSet);
dataSets.add(circularDataSet);
This just prints a dot(circularDataSet) and not the scoreDataSet. I was expecting it to merge both the DataSets so as to mark the highest value with a circle and drawing the rest as a line chart.
Your approach looks good in general, there are just a few flaws.
Don't create the "circularDataSet" and initialize it with the same values like the "scoreDataSet" and then remove all except one.
What you should do instead is find the largest entry in your "scoreDataSet", and then only add this single entry to the "circularDataSet".

How to hide legends and axis in MPAndroidChart?

Is their any possibility to hide all rounded items from this picture.
I have used the following code,
public void setDataList(List<HorizontalBarChartData> dataList, Resources resources) {
ArrayList<String> categories = new ArrayList<String>();
ArrayList<BarEntry> values = new ArrayList<BarEntry>();
ArrayList<BarDataSet> dataSets = new ArrayList<BarDataSet>();
BarDataSet set1;
for (int i = 0; i < dataList.size(); i++) {
categories.add(dataList.get(i).getName());
values.add(new BarEntry(dataList.get(i).getValue(), i));
}
/*set1 = new BarDataSet(values, "Income, Expense, Disposable Income");*/
set1 = new BarDataSet(values, "Category 1, Category 2, Category 3");
set1.setBarSpacePercent(35f);
set1.setColors(new int[]{resources.getColor(R.color.cyan_blue), resources.getColor(R.color.vermilion_tint), resources.getColor(R.color.sea_green)});
dataSets.add(set1);
BarData data = new BarData(categories, dataSets);
data.setValueTextSize(10f);
horizontalBarChart.setData(data);
}
Update
How to hide rounded part from this image?
Yes, is possible, just using following code:
mChart.setDescription(""); // Hide the description
mChart.getAxisLeft().setDrawLabels(false);
mChart.getAxisRight().setDrawLabels(false);
mChart.getXAxis().setDrawLabels(false);
mChart.getLegend().setEnabled(false); // Hide the legend
As per this answer
mChart.getXAxis().setDrawLabels(false); will hide the entire X-Axis(as required for this question).
For positioning the X-Axis, following code works.
XAxis xAxis = mChart.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
Position can be set to
BOTTOM
BOTH_SIDED
BOTTOM_INSIDE
TOP
TOP_INSIDE
This helps if you are trying to hide only the particular side axis instead of hiding the entire axis.
It appears mChart.setDescription() no longer accepts a String.
The method now accepts an instance of the Description Class like this:
mChart.setDescription(Description description)
So to modify or delete the Chart Description you may do it like below
Description description = new Description();
description.setText("");
mChart.setDescription(description);
Following code work for all chart
Legend l = mchart.getLegend();
l.setEnabled(false);.
To hide description, use this
mChart.getDescription().setEnabled(false)
Below code works for PieChart. Try to get same method for your Chart.
Legend l = mChart.getLegend();
l.setPosition(LegendPosition.NONE);
chart=(LineChart) findViewById(R.id.Chart);
chart.getLegend().setEnabled(false); // for hiding square on below graph
Kotlin solution for MPAndroidChart:v3.1.0
chart.description.isEnabled = false // hide the description
chart.legend.isEnabled = false // hide the legend
chart.xAxis.setDrawLabels(false) // hide bottom label
chart.axisLeft.setDrawLabels(false) // hide left label
chart.axisRight.setDrawLabels(false) // hide right label
I had the problem, that the bottom xAxis Labels are cutted off when I used mChart.getLegend().setEnabled(false)
Now I use chart.getLegend().setForm(Legend.LegendForm.NONE); instead and the labels are not cutted of anymore

MPAndoirdChart Piechart how not to show bottom labels?

How not to show the highlighted bottom labels in pie chart?
And how to change entries text color?
You can do that by setting the setDrawLegend property to false.
Wherever you initialize your pieChart just add the following line:
pieChart.setDrawLegend(false);
[EDIT]
About changing the colors this is what you can do:
First of all this is happening when you add some data to your chart. When you add the data you add a PieData object to the chart. This PieData object takes 2 arguments, the names, and the values. The list of names is an ArrayList of Strings, but the values need to be an instance of a PieDataSet object. This is where you can add the colors and add other properties as well(such as the spacing between slices). Also, the PieDataSet object wraps up the Y values of a set and the label for this. And finally the PieDataSet's values are an ArrayList of Entry objects. One single Entry object takes the value to be shown, and it's index on the chart.
Here is a sample DEMO code that illustrates the above short description:
ArrayList<Entry> yChartValues = new ArrayList<Entry>();
int[] chartColorsArray = new int[] {
R.color.clr1,
R.color.clr2,
R.color.clr3,
R.color.clr4,
R.color.clr5
};
// These are the 2 important elements to be passed to the chart
ArrayList<String> chartNames = new ArrayList<String>();
PieDataSet chartValues = new PieDataSet(yChartValues, "");
for (int i = 0; i < 5; i++) {
yChartValues.add(new Entry((float) i*2, i));
chartNames.add(String.valueOf(i));
}
chartValues.setSliceSpace(1f); // Optionally you can set the space between the slices
chartValues.setColors(ColorTemplate.createColors(this, chartColorsArray)); // This is where you set the colors. The first parameter is the Context, use "this" if you're on an Activity or "getActivity()" if you're on a fragment
// And finally add all these to the chart
pieChart.setData(new PieData(chartNames, chartValues));
Does this help?
Edit 2:
This is how you change the color of the text inside the pie-slices:
PieChart pieChart = ...;
// way 1, simply change the color:
pieChart.setValueTextColor(int color);
// way 2, acquire the whole paint object and do whatever you want
Paint p = pieChart.getPaint(Chart.PAINT_VALUES);
p.setColor(yourcolor);
I know this is not an ideal solution, but it should work for now.

Categories

Resources