I am using MPChart for displaying a Barchart. My values are positive and negative. I want to show xAxis as used in Math of traditional way. Using this code my chart display vertical lines (only zero wanted)
mXAxis = mChart.getXAxis();
mXAxis.setDrawGridLines(false);
mXAxis.setEnabled(false);
mYAxis = mChart.getAxisLeft();
mYAxis.setDrawAxisLine(false);
mYAxis.setDrawGridLines(true);
mYAxis.setStartAtZero(false);
mYAxisRight = mChart.getAxisRight();
mYAxisRight.setEnabled(false);
mYAxisRight.setDrawGridLines(false);
Please, provide some sample for removing all horizontal lines but zero
EDIT:
Even when yAxis.setLabelCount(1) (1 because zero value needed to shown) the impl looks like:
public void setLabelCount(int yCount) {
if(yCount > 25) {
yCount = 25;
}
if(yCount < 2) {
yCount = 2;
}
this.mLabelCount = yCount;
}
So, is it recommended to override this implementation?
I have got solution with labels at bottom
Use this in your code
mXAxis = mChart.getXAxis();
mXAxis.setDrawGridLines(false);
mXAxis.setEnabled(true);
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
Related
I want to display X-axis labels only on the top of my chart. How can I do it?
I'm using this code:
XAxis xAxis = chart.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.BOTH_SIDED);
xAxis.setDrawLabels(false);
And this is result:
Or If I do this
XAxis xAxis = chart.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.TOP);
xAxis.setDrawAxisLine(true);
Then I have labels only on the top BUT the bottom line is missing.
You want to display xAxis lines for position BOTH_SIDED but without labels on the bottom, so you need to override XAxisRenderer:
chart.getXAxis().setPosition(XAxis.XAxisPosition.BOTH_SIDED);
chart.setXAxisRenderer(new XAxisRenderer(chart.getViewPortHandler(), chart.getXAxis(), chart.getTransformer(YAxis.AxisDependency.LEFT)) {
#Override
public void renderAxisLabels(Canvas canvas) {
if (!mXAxis.isEnabled()|| !mXAxis.isDrawLabelsEnabled())
return;
MPPointF pointF = MPPointF.getInstance(0f, 0f);
mAxisLabelPaint.setTypeface(mXAxis.getTypeface());
mAxisLabelPaint.setTextSize(mXAxis.getTextSize());
mAxisLabelPaint.setColor(mXAxis.getTextColor());
pointF.x = 0.5f;
pointF.y = 1.0f;
drawLabels(canvas, mViewPortHandler.contentTop() - mXAxis.getYOffset(), pointF);
}
});
This won't help the original author, but I had the same issue and fixed it with
chart.setExtraBottomOffset(-40f);
Nice, simple, worth a try. You may need to tune the value to suit your aesthetic.
I am a bit new to MPAndroidChart library and I am going to make a line chart for my data. I intend to set yaxis values exactly in the center of each grid rectangle which is inside them.
How that would be possible ?
I am actually trying to do this also,get the Y values show up above the graph in the center X axis, but I was having trouble. I know you have to override the draw method in your MarkerView class, the code I was using is below. Maybe you can play with it and get the results you need. Other questions about this I was looking at had posX = getXoffset() & posY = 0 but for some reason I wasn't able to get the getXoffset() Override method.
#Override
public void draw(Canvas canvas, float posX, float posY) {
posX = 400;
posY = -30;
canvas.translate(posX,posY);
draw(canvas);
canvas.translate(-posX,-posY);
}
I am not getting what exactly do you want. Try this:
lineChart.getXAxis().setCenterAxisLabels(true);
Right Now I am facing this issue. I am getting repeated values in xAxis the first one and the last one.And graph values are not according to the values at respective x-axis values.
and the second issue is if I want to display the values not in float but in int Rounded and change the their color to white.
ArrayList<String> xlabels = new ArrayList<String>();
xlabels.add("Jan");
xlabels.add("Feb");
xlabels.add("Mar");
xlabels.add("Apr");
xlabels.add("May");
xlabels.add("Jun");
ArrayList<String> values = new ArrayList<String>();
values.add("1");
values.add("20");
values.add("10");
values.add("80");
values.add("90");
values.add("24");
showLineChart(clickChart,xlabels,values,mColors[3]);
showLineChart Method:
private void showLineChart(LineChart chart,final List<String> xLabels, List<String> values,int color){
List<Entry> entries = new ArrayList<Entry>();
for(int i=0;i<values.size();i++){
entries.add(new Entry(i, Integer.parseInt(values.get(i))));
}
LineDataSet dataSet = new LineDataSet(entries, "Numbers");
dataSet.setLineWidth(1.75f);
dataSet.setCircleRadius(5f);
dataSet.setCircleHoleRadius(2.5f);
dataSet.setColor(Color.WHITE);
dataSet.setCircleColor(Color.WHITE);
dataSet.setHighLightColor(Color.WHITE);
dataSet.setDrawValues(true);
LineData data = new LineData(dataSet);
((LineDataSet) data.getDataSetByIndex(0)).setCircleColorHole(color);
chart.getDescription().setEnabled(false);
chart.setDrawGridBackground(false);
chart.setTouchEnabled(true);
chart.setBorderColor(Color.WHITE);
chart.setDragEnabled(true);
chart.setScaleEnabled(true);
chart.setPinchZoom(false);
chart.setBackgroundColor(color);
YAxis yAxisLeft = chart.getAxisLeft();
yAxisLeft.setTextColor(Color.WHITE);
yAxisLeft.setAxisLineColor(Color.WHITE);
YAxis yAxisRight = chart.getAxisRight();
yAxisRight.setTextColor(Color.WHITE);
yAxisRight.setAxisLineColor(Color.WHITE);
XAxis xAxis = chart.getXAxis();
xAxis.setTextColor(Color.WHITE);
xAxis.setAxisLineColor(Color.WHITE);
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
xAxis.setAvoidFirstLastClipping(false);
xAxis.isDrawLabelsEnabled();
xAxis.setDrawGridLines(false);
xAxis.setValueFormatter(new IAxisValueFormatter() {
#Override
public String getFormattedValue(float value, AxisBase axis) {
return xLabels.get((int)value);
}
});
chart.animateX(2500);
chart.setData(data);
chart.invalidate();
}
I was facing the same issue to resolve it add the following line:
xAxis.setGranularityEnabled(true);
Check the link for more details about Axis.
Setting granularity alone did not solve my problem. Here's what I had to do:
XAxis xAxis = chart.getXAxis();
xAxis.setGranularity(1f);
xAxis.setGranularityEnabled(true);
xAxis.setLabelCount(xLabels.size(),false); // yes, false. This is intentional
xAxis.setValueFormatter(new MyXAxisValueFormatter(xLabels));
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
And, this is my simple implementation of the IAxisValueFormatter. You may change it as per your needs:
public class MyXAxisValueFormatter implements IAxisValueFormatter {
private ArrayList<String> mValues;
MyXAxisValueFormatter(ArrayList<String> values) {
this.mValues = values;
}
#Override
public String getFormattedValue(float value, AxisBase axis) {
int index = Math.round(value);
if(index >= mValues.size()){
index = mValues.size()-1;
}
return mValues.get(index);
}
}
It's very important to know why every problem occurs and why the solution code solves the problem. So, here's the analysis part:
Why does this occur?
Even in cases where your data lies at whole number positions on the x-axis (0,1,2...), the actual label isn't necessarily placed at those specific positions. For example, the label for the data at 1.00f might be at 0.92f. (This is how the library handles it, not sure why). So, when you try to cast the float value to an int, you do not get the exact position. From the earlier example, the label at 0.92f when cast to an int would be a 0, not 1.
How does this code solve the problem?
If you understood the above section, then this must not be necessary. Anyways, here's the reasoning. From my test results, I noticed that the label position was at all times nearby the actual x. So, the Math.round() method was perfect to get the proper index out of the float value.
Additionally, I set the parameter forced as a false in the setLabelCount method because I wanted the labels to hide as the user zooms-in in the x-axis.
//set granularity to minimum value to ensure label does not give duplicate value
lineChart.getAxisLeft().setGranularity(1f);
lineChart.getXAxis().setGranularity(1f);
lineChart.getXAxis().setGranularityEnabled(true);
//also make sure you don't pass true as force parameter in below line please pass only false
bottomAxis.setLabelCount(dateLabels.size(),false);
For set Y values I used this code snippet
ArrayList<Entry> yVals = new ArrayList<Entry>();
int sizeOfY = analyticsWeek.getGraph().size();
if (sizeOfY > 7)
sizeOfY = 7;
for (int i = 0; i < sizeOfY; i++) {
Log.e("sizeOfY",analyticsWeek.getTitle()+":"+i);
yVals.add(new Entry(Float.parseFloat("0"), i));
}
It shows middle of graph with 0.0 values instead of show at aligned to xAxis when (0,1),(0,2) where (pointValue,Xaxis). As shown in image it comes in center of graph even if there is zero point values. It should be aligned to xAxis
Have you set axis dependency?
dataSet.setAxisDependency(AxisDependency.RIGHT);
You should set the minimum value of your axis to 0 using setAxisMinValue, like this:
mChart.getAxisLeft().setAxisMinValue(0);
mChart.getAxisRight().setAxisMinValue(0);
Note: Starting with version 3.0.0 of the library this has been renamed to setAxisMinimum:
mChart.getAxisLeft().setAxisMinimum(0);
mChart.getAxisRight().setAxisMinimum(0);
chartObject.getAxisLeft().setAxisMinValue(0.0f);
Works well for me!
I want to avoid the repeated values and the -0 values in Y-Axis, avoiding the image situation.
I have these ideas to solve this, but any solution:
Limit the zoom before having repeated values in YAxis, therefore stop the infinite zoom-in on the chart
Get the YAxis values and remove the duplicate values.
Though this is an older question I'd like to add to it for future reference. Newer versions of the library have a little known feature that resolves the duplicated labels, called granularity. This is way simpler to use than the older solutions (though to be fair, this wasn't available at the time those were posted).
You can always check the latest AxisBase Javadocs (3.0.0-beta1) for a more detailed explanation. Here are the relevant methods:
setGranularity(float granularity):
Set a minimum interval for the axis when zooming in. The axis is not
allowed to go below that limit. This can be used to avoid label
duplicating when zooming in.
setGranularityEnabled(boolean enabled):
Enabled/disable granularity control on axis value intervals. If
enabled, the axis interval is not allowed to go below a certain
granularity.
So in your case you'd need to set the granularity to 0.1f since you have one decimal point. The following snippet of code should avoid the repeated values on the axis:
YAxis yAxis = mChart.getAxisLeft();
yAxis.setGranularityEnabled(true);
yAxis.setGranularity(0.1f);
tl;dr You can do this by changing the label count in onChartScale.
First, you want your listener set up:
chart.setOnChartGestureListener(this); // set a listener ;)
You try to get the top/bottom drawn values and check what gets drawn on the screen. Apply some basic calculations, and you're set.
The following code will draw 2 labels if the zoom level gets (too) high and up to 9 otherwise:
#Override
public void onChartScale(MotionEvent me, float scaleX, float scaleY) {
final YAxis yAxis = mChart.getAxisLeft();
final Transformer transformer = mChart.getTransformer(YAxis.AxisDependency.LEFT);
// ...minor dirty hack
final PointD top = transformer.getValuesByTouchPoint(0, 0);
final PointD bottom = transformer.getValuesByTouchPoint(0, mChart.getHeight());
final int diff = (int)(top.y - bottom.y);
// draw 2-9 axis labels
final int count = Math.min(9, Math.max(diff, 2));
Log.d("scale", String.format("scale %f: diff %d and count %d", scaleY, diff, count));
// "force" the count, for there are drawing issues where none get drawn on high zoom levels (just try it out)
yAxis.setLabelCount(count, true);
}
// todo implement other interface methods
The value formatter and everything else stays the same.
And some ugly screenshot to show that it works :D
code like this:
mchart.setAutoScaleMinMaxEnabled(false);
mchart.getAxisLeft().setAxisMaxValue(10);
mchart.getAxisLeft().setAxisMinValue(5);
mchart.getAxisRight().setAxisMaxValue(10);
mchart.getAxisRight().setAxisMinValue(5);
or:
boolean a = isReady;
mchart.getAxisLeft().setFormater(new format(float b){ return "" ;})
When u get data :
mchart.setAutoScaleMinMaxEnabled(true);
mchart.getAxisLeft().resetAxisMaxValue();
mchart.getAxisLeft().resetAxisMinValue();
mchart.getAxisRight().resetAxisMaxValue();
mchart.getAxisRight().resetAxisMinValue(5);
I have no code by my hand.
You can set granularity to your required value to prevent the repetition when zoomed.
mBarChart.getAxisLeft().setGranularity(1f); // y-axis scale will be 0,1,2,3,4....
mBarChart.getAxisLeft().setGranularityEnabled(true);
If you want to set granularity dynamically, then implement IAxisValueFormatter and compare the return value to get the difference and set Granularity to that difference.
private float yAxisScaleDifference = -1;
private boolean granularitySet = false;
//say the values returned by IAxisFormatter is in hundreds: 100, 200, 300...
mBarChart.getAxisLeft.setValueFormatter(new IAxisValueFormatter() {
#Override
public String getFormattedValue(float v, AxisBase axisBase) {
if(!granularitySet) {
if(yAxisScaleDifference == -1) {
yAxisScaleDifference = v; //10
}
else {
float diff = v - yAxisScaleDifference; //200 - 100 = 100
if(diff >= 1000) {
yAxisLeft.setGranularity(1000f);
}
else if(diff >= 100) {
yAxisLeft.setGranularity(100f); //set to 100
}
else if(diff >= 1f) {
yAxisLeft.setGranularity(1f);
}
granularitySet =true;
}
}
return val;
}
});
Another Example:
say Y-Axis returns [1200,3400,8000,9000....]
first time: 1200
second time: 3400 - 1200 = 2200
granularity set to 1000
If the difference is not uniform you have to use array to store the differences and take the average to get the right granularity.
If you are using IAxisValueFormatter the problem might be in the conversion of float to Int when trying to access the values array.
For me the solution was to
IAxisValueFormatter numAppointmentsXAxisFormatter = new IAxisValueFormatter() {
#Override
public String getFormattedValue(float value, AxisBase axis) {
int index = (int)Math.ceil(value);
if(index < 0){
index = 0;
}else if(index >= numAppointmentsLabels.size()){
index = numAppointmentsLabels.size()-1;
}
return numAppointmentsLabels.get(index);
}
};
I also added +1 to the label count
chart.getXAxis().setLabelCount(numValue+1, true);
Hope it helps
I have never used MPAndroidCharts before, but just a little search here and there got me this method which I think would be useful.
public void setLabelCount(int count, boolean force) {
if (count > 25)
count = 25;
if (count < 2)
count = 2;
mLabelCount = count;
mForceLabels = force;
}
The description says that "exact specified count of labels will be drawn and evenly distributed alongside the axis". If you can make it work in your favor, you might be able to limit the zoom.
Also, there is another method-
public int getLabelCount() {
return mLabelCount;
}
This returns the number of labels on the axis. Hope this helps.
https://github.com/PhilJay/MPAndroidChart/blob/5a15715b25991e3d61d27d552f9eba45975d65e7/MPChartLib/src/com/github/mikephil/charting/components/YAxis.java