PhilJay / MPAndroidChart

A powerful ๐Ÿš€ Android chart view / graph view library, supporting line- bar- pie- radar- bubble- and candlestick charts as well as scaling, panning and animations.
Other
37.51k stars 9.01k forks source link

Date on X axis. #789

Closed joshisunil-1983 closed 9 years ago

joshisunil-1983 commented 9 years ago

hi, i am using MPandroid chart in my app. i want to plot chart using values on y axis and date on x axis. I don't find any datetime axis in mp android chart. is there any way to plot x axis using date. i have values against date. i want to show the dates in (ddMMM-yy) format on x axis and the values on y axis. anyone can pass me the sample link for the same.

sample for data: Date(X axis) Value(Y axis) 01/01/2001 966.78 01/02/2001 666.78 01/03/2001 966.78 01/04/2001 966.78 01/05/2001 966.78 01/06/2001 966.78 01/07/2001 966.78

guide.

PhilJay commented 9 years ago

Set this "01/01/2001" and so on as an x-axis label, place your values to the correct x-indices

silviul commented 9 years ago

I have literally done this today. It's quite easy. Labels on the X Axis can be whatever strings. I converted a list of dates to my preferred format and set them as the X values like so: LineData lineData = new LineData(xValues);. You then have to set values to corresponding indices, like @PhilJay said before.

PhilJay commented 9 years ago

@silviul Did you do that for Shazam? Or something else?

silviul commented 9 years ago

@PhilJay I'm just playing with the library. Not for Shazam.

WalkerWalker commented 8 years ago

I'm hoping for the exact function. Not only what I want date as string, but I hope the date label can be dynamically according to zoom gestures. For example, if I'm showing one year of data, I want the label as months but if I zoomed in and is only showing one month of data, then the label could be days. Is it possible to achieve this with overriding some methods?

PhilJay commented 8 years ago

Now possible:

https://github.com/PhilJay/MPAndroidChart/blob/master/MPChartExample/src/com/xxmassdeveloper/mpchartexample/BarChartActivity.java

Example formatter:

https://github.com/PhilJay/MPAndroidChart/blob/master/MPChartExample/src/com/xxmassdeveloper/mpchartexample/custom/DayAxisValueFormatter.java

griffins commented 8 years ago

That seems to BE working only for the bar chart or am getting something wrong??

WalkerWalker commented 8 years ago

@Griffins The api just updated thoroughly and the documentation is out of date, as said here. This confuses me for the whole morning.

But I kind of like the new way, treating X and Left and Right Axis all the same. And if you want to show some special labels according to the data, on any axis, use the formatter. Just hope the new documentation will be out soon. @PhilJay

oscarcuenca commented 8 years ago

Hi. I have a list in Array of 480 date and time each day (timestamp). I would like to fix this in X axi, How can do it automatically (not typing one by one) I get in ansyncronic process it, if "labels" are fixed OnCreate, means it is filled before I get data later on ansyncronic task... Any code exemple to help me...

manmohan556 commented 8 years ago

How to give two space between two bars in stacked bar.And total count on top of bar .I am using .PhilJay:MPAndroidChart:v3.0.0-beta1'.Please help me

Yasir-Ghunaim commented 8 years ago

Note: below solution was implemented using the following version:

compile 'com.github.PhilJay:MPAndroidChart:v3.0.0-beta1'

This workaround is based on the implementation of "DayAxisValueFormatter.java" suggested previously by @PhilJay. Final result looks like this:

screenshot

Steps:

1. Expressing x values in timestamps:

Say, for example, we have this data set:

x y
2016-01-01 15:00:00 GMT 25
2016-01-01 22:00:00 GMT 58
2016-01-02 08:00:00 GMT 36
2016-01-02 14:00:00 GMT 12
2016-01-02 19:00:00 GMT 29

We would like to populate a MPAndroidChart LineChart instance with above date set but we can only do so using a float type in the form: Entry(float x, float y). One easy way to handle this obstacle is to convert all dates to timestamps to get this result:

x y
1451660400 25
1451685600 58
1451721600 36
1451743200 12
1451761200 29

Now, it seems like we should be good to go but one final adjustment is still required. When I tried these huge x values, my chart became really slow especially when zooming in and out.

2. Converting timestamps to small numbers:

As a solution to this, we can further manipulate these x values by using this conversion:

Xnew = Xold - reference_timestamp

First timestamp in a sorted data set should be the minimum timestamp which can be perfectly used as a zero reference. In that case, if we apply this equation to our sorted data set such as:

reference_timestamp = 1451660400

we get this new data set:

x y
0 25
25200 58
61200 36
82800 12
100800 29

We can even reduce these numbers by converting from seconds timestamps to minutes timestamps if that is really needed.

Make sure to keep reference_timestamp stored in a global variable so that you can retrieve your original timestamp when needed.

3. Applying ValueFormatter to show x labels of hours and minutes:

At this moment, your chart should be working smoothly but your x axis will show labels that has no meaning to your user. Let's add some meaning to our x axis by using this value formatter which provides a nice label to our dataset in hours and minutes (HH:mm): HourAxisValueFormatter.java

You can apply it in this way:

AxisValueFormatter xAxisFormatter = new HourAxisValueFormatter(referenceTimestamp);
XAxis xAxis = mChart.getXAxis();
xAxis.setValueFormatter(xAxisFormatter);

4. Set a MarkerView to show a popup containing the full date and time when a value is highlighted:

More details about MarkerView can be found here wiki.

Use MyMarkerView.java to show full date and time when a value is pressed. Implementation is easy just call setMakerView() like this:

MyMarkerView myMarkerView= new MyMarkerView(getApplicationContext(), R.layout.my_marker_view_layout, referenceTimestamp);
mChart.setMarkerView(myMarkerView);

R.layout.my_marker_view_layout is found here: custom_marker_view.xml and @drawable/marker2 is found here: marker2.png

gmkdev commented 7 years ago

hi yasir can you gave me some example?

LeslieJG commented 7 years ago

Can you give an XML example of your MyMarkerView layout? I would like to know how you got the nice triangle at the bottom?

Yasir-Ghunaim commented 7 years ago

@gmkdev Please refer to my last comment. I revised the whole comment and provided more explanations.

@LeslieJG I added more details about MyMarkerView layout in my last comment. See last two lines. Best of luck.

hammad-tariq commented 7 years ago

@Yasir-Ghunaim I am doing exactly same but i want to ask why x -axis values do not start from zero. means why your first value is away from origin ? can we force it to start from origin for first value ?

Yasir-Ghunaim commented 7 years ago

@hammadtariqsahi Actually, my x-axis values start from 0 (refer to data set shown in the second step in my guide). The formatted (HH:mm) x values you are seeing in the provided screenshot are simply a result of a ValueFormatter that translates the converted timestamps (x values) to a more user friendly format.

sunilMyUniverse commented 7 years ago

Hi phil, I want to set dates to xAxis ,How can I achieve this?

ashwinipawar1710 commented 7 years ago

i want to set dates to xaxis on the bar,how can i achieve this?

LasseOnTheHub commented 7 years ago

@ashwinipawar1710 You can format the SimpleDateFormat as you wish in @Yasir-Ghunaim ' s HourAxisValueFormatter like this where i show the date before the time.

public HourAxisValueFormatter(long referenceTimestamp) { this.referenceTimestamp = referenceTimestamp; this.mDataFormat = new SimpleDateFormat("dd-HH:mm", Locale.ENGLISH); this.mDate = new Date(); }

image Dont mind the broken marker and generally poor design.

janmarlon commented 7 years ago

barchart

@PhilJay look at may captured codes. I am new with mpandroidchart library, I am currently developing an application with bar graphs. I want to set my xVal as dates. but it seems BarData is not accepting a string parameter. hope you response ASAP. Thank you and God bless

janmarlon commented 7 years ago

@PhilJay Is setting data in bar chart is different from linechart? I watched some tutorials and tried their codes, but it did not work with my project. I'm having an error with the parameter in BarData. when I removed the "labels" as parameter in BarData and left the "set" parameter, it properly works. and i tried it also with LineChart, LineData accepts 2 parameters. only in BarChart I am having a trouble. Please help me. Thanks!

janmarlon commented 7 years ago

@PhilJay please do notice me. ty

garimawadhera commented 7 years ago

http://stackoverflow.com/questions/41716677/getting-error-in-implementing-dayaxisvalueformatter-using-mpandroidchart Please resolve this @PhilJay

Malikkhoja-zz commented 7 years ago

@Yasir-Ghunaim As per the reference given by you for the time support on X-Axis(#789). I m using your solution exactly for Multi line chart. But the data on my X Axis is repetitive and not in the correct order. I am not sure why this is happening. I have already asked the question with the details of the data that i m using to plot the graph. Please look at the issue : #2775

It would be great if u can help me with the solution. Thanks

ashish411 commented 7 years ago

@Yasir-Ghunaim in your demonstration when you converted dates to Timestamps how do you pass them in the Entry method which requires float value ?

DivyaBansal commented 7 years ago

@Yasir-Ghunaim Thank you for the wonderful solution. But the methods in the MarkerView class in Phil's code has changed. How do I incorporate these changes in your code?

Yasir-Ghunaim commented 7 years ago

@DivyaBansal Could you point out which methods were changed as I am not keeping up with latest updates?

Alternatively, refer to this version that I initially used:

compile 'com.github.PhilJay:MPAndroidChart:v3.0.0-beta1'

and compare MarkerView methods in this version against latest version.

ewertonluizmenesesrocha commented 7 years ago

@Yasir-Ghunaim
How do I create a label for when I touch the screen on one of the scales the values โ€‹โ€‹of the x and y axis appear? As the one that appears a value 50% and the date in LineChart?

75214e42-68ab-11e6-8602-c94e1e65a7f1

hiteshsahu commented 7 years ago

Marker arrow was not consistent so I did it in alternate approach

Example with Android Toast

device-2017-05-19-153743

Steps

  1. Let your parent activity containing chart implements OnChartValueSelectedListener

public class APrioriResultActivity extends AppCompatActivity implements OnChartValueSelectedListener

  1. Then assign your activity class to bar chart as OnChartValueSelectedListener

barChart.setOnChartValueSelectedListener(this);

  1. and then implement onValueSelected method to paint data on screen in whichever way you like ie- Toast, Snack bar, dialog, TextView etc

    Toast mCurrentToast;
    
    @Override
    public void onValueSelected(Entry e, Highlight h) {
    
        if (mCurrentToast != null) {
            mCurrentToast.cancel();
        }
    
        mCurrentToast = Toast.makeText(this, "Support for" +
                        setEntries.get(Math.round(e.getX())) + " is " + e.getY(),
                Toast.LENGTH_LONG);
        mCurrentToast.show();
    }
    
     @Override
      public void onNothingSelected() {
    
      }
abhishek-bharadwaj commented 7 years ago

If anyone using compile 'com.github.PhilJay:MPAndroidChart:v3.0.2' I made couple of changes in @Yasir-Ghunaim 's solution AxisValueFormatter is not there anymore so use this

HourAxisValueFormatter axisFormatter = new HourAxisValueFormatter(minTimeStamp); chart.getXAxis().setValueFormatter(axisFormatter);

package com.healthifyme.basic.diy_reports;

import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
 * Created by Abhishek on 08/06/17.
 */
public class HourAxisValueFormatter implements IAxisValueFormatter {

    private long referenceTimestamp; // minimum timestamp in your data set
    private DateFormat mDataFormat;
    private Date mDate;

    public HourAxisValueFormatter(long referenceTimestamp) {
        this.referenceTimestamp = referenceTimestamp;
        this.mDataFormat = new SimpleDateFormat("HH:mm", Locale.ENGLISH);
        this.mDate = new Date();
    }

    /**
     * Called when a value from an axis is to be formatted
     * before being drawn. For performance reasons, avoid excessive calculations
     * and memory allocations inside this method.
     */

    @Override
    public String getFormattedValue(float value, AxisBase axis) {
        // convertedTimestamp = originalTimestamp - referenceTimestamp
        long convertedTimestamp = (long) value;

        // Retrieve original timestamp
        long originalTimestamp = referenceTimestamp + convertedTimestamp;

        // Convert timestamp to hour:minute
        return getHour(originalTimestamp);
    }

    private String getHour(long timestamp) {
        try {
            mDate.setTime(timestamp * 1000);
            return mDataFormat.format(mDate);
        } catch (Exception ex) {
            return "xx";
        }
    }
}
adriamt commented 7 years ago

I have an implementation like this, but the problem is that the labels are not equally spaced. For example I want labels like '11:00' , '11:30' , '12:00', '12:30' ,etc and I'm getting 10:59 , 11:31, 12:04, 12:29, etc. Any clue how to achieve this @Yasir-Ghunaim ? Here is a capture of what I'm talking. screenshot_20170704-172319_2

Yasir-Ghunaim commented 7 years ago

@adriamt I noticed this problem earlier but didn't know how to fix it. Based on several experiments, existing algorithm places labels at multiples of 100s, 1000s, 5000s which doesn't look nicely with seconds and minutes. I think one way would be to explore AxisBase and ComponentBase classes and see whether you can manipulate their algorithm so that labels are positioned at every an hour or at every multiple of 3600 (i.e. at 3600, 7200, etc).

Once you achieve that, you might want to provide an offset to this labeling mechanism so that if your reference timestamp doesn't start at the exact beginning of an hour, you could simply shift the multiples of 3600 to match your data set structure.

sonczyponcze commented 7 years ago

Workaround for putting dates [String] on XAxis, maintaining proportional spacing:

Dashing-Daniel-Li commented 6 years ago

How would you go about putting on the x axis the day and inbetween days the time in hh:mm ??

gxlinda commented 6 years ago

Is it possible to write date on X axis in two lines? For example like this: 2017 12.10

CG-Vivek commented 6 years ago

@gxlinda save the date string using " \n " between 2017 and 12.10

toFormatter.dateFormat = "hh:mm a \n dd/MM/yy"

karansingla007 commented 5 years ago

is it possible to show the only month in xAxis? and set (highlighter) label when a user clicks nearby points.

CG-Vivek commented 5 years ago

yes it is possible, you can provide xAxis data Array to be displayed. myChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values:XaxisDataArray)

karansingla007 commented 5 years ago

Where can I use xAxis data array

On Fri, Sep 28, 2018, 4:35 PM CG-Vivek notifications@github.com wrote:

yes it is possible, you can provide xAxis data Array to be displayed.

โ€” You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/PhilJay/MPAndroidChart/issues/789#issuecomment-425401755, or mute the thread https://github.com/notifications/unsubscribe-auth/AY20_hnJjEYtf3KS_xp_gyF9te6MqCksks5ufgJ-gaJpZM4FIO6X .

khalidelq commented 5 years ago
screen shot 2018-10-11 at 18 35 15

Can you help me, i have a probleme with date truncate, for exemple (06/09) and that is my code: public class CombinedChartAdria extends CombinedChart {

private CombinedChart mChart;
private ArrayList<Entry> entriesLine;
private ArrayList<BarEntry> entriesBar;
private List<ChartModel> chartModels;
private int positifColor, negatifColor;
private int mRadius;

public CombinedChartAdria(Context context) {
    super(context);
}

public CombinedChartAdria(Context context, AttributeSet attrs) {
    super(context, attrs);
    mRadius = attrs.getAttributeIntValue("http://schemas.android.com/apk/res-auto", "rounded", 0);
}
public void initChart(final List<ChartModel> chartModels) {
    this.chartModels = chartModels;
    entriesLine = new ArrayList<>();

    mChart = findViewById(R.id.chart);
    mChart.setHighlightFullBarEnabled(false);

    // draw bars behind lines

    YAxis rightAxis = mChart.getAxisRight();
    rightAxis.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART);
    rightAxis.setDrawLabels(false); // no axis labels
    rightAxis.setDrawAxisLine(false); // no axis line
    rightAxis.setDrawGridLines(false); // no grid lines
    rightAxis.setTypeface(Utils.getTypeFaceRegular(this.getContext()));
    rightAxis.setDrawZeroLine(true); // draw a zero line
    rightAxis.setGridLineWidth(0.5f);

    YAxis leftAxis = mChart.getAxisLeft();
    leftAxis.setDrawLabels(true); // no axis labels
    leftAxis.setDrawAxisLine(false); // no axis line
    leftAxis.setDrawGridLines(false); // no grid lines
    leftAxis.setTextSize(6f);
    leftAxis.setTextColor(getResources().getColor(R.color.txtMainColor));
    leftAxis.setTypeface(Utils.getTypeFaceRegular(this.getContext()));
    leftAxis.setDrawZeroLine(true); // draw a zero line
    leftAxis.setGridLineWidth(1f);

    XAxis xAxis = mChart.getXAxis();
    xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
    xAxis.setDrawLabels(true); // no axis labels
    xAxis.setDrawAxisLine(false); // no axis line
    xAxis.setDrawGridLines(false); // no grid lines
    xAxis.setTextSize(6f);
    xAxis.setTextColor(getResources().getColor(R.color.txtMainColor));
    xAxis.setTypeface(Utils.getTypeFaceRegular(this.getContext()));
    xAxis.setGranularity(1f);
    xAxis.setLabelRotationAngle(-90);
    xAxis.setCenterAxisLabels(false);
    xAxis.setAxisMinimum(0);
    xAxis.setGranularityEnabled(false);
    xAxis.setValueFormatter(new IAxisValueFormatter() {
        @Override
        public String getFormattedValue(float value, AxisBase axis) {
            return  chartModels.get((int) value).getLabel();
        }

    });

    xAxis.setLabelCount(chartModels.size());
    CombinedData data = new CombinedData();
    data.setData(generateLineData());
    data.setData(generateBarData());
    xAxis.setAxisMinimum(data.getXMin() - 0.5f);
    xAxis.setAxisMaximum(data.getXMax() + 0.5f);
    //mChart.setViewPortOffsets(-10f, 0f, 0f, -10f);
    this.animateXY(1000, 1000);

    Paint paint = this.getRenderer().getPaintRender();
    int height = 200;
    LinearGradient linGrad = new LinearGradient(0, 0, 0, height,
            getResources().getColor(R.color.colorRedGradient),
            getResources().getColor(R.color.colorGradient2),
            Shader.TileMode.CLAMP);
    paint.setShader(linGrad);
    this.setData(data);
    this.invalidate();
}
private LineData generateLineData() {
    entriesLine = new ArrayList<>();
    positifColor = getResources().getColor(R.color.colorBgDark);
    negatifColor = getResources().getColor(R.color.graphBodyColor);
    for (ChartModel chartModel : chartModels)
        entriesLine.add(chartModel.getBarEntry());
    final ArrayList<Integer> listColor = new ArrayList<>();
    for (Entry entry : entriesLine) {
        listColor.add(entry.getY() < 0 ? negatifColor : positifColor);
    }
    LineDataSet dataset = new LineDataSet(entriesLine, "label");
    dataset.setDrawValues(false);
    dataset.setDrawFilled(false);
    dataset.setMode(LineDataSet.Mode.LINEAR); // Line type
    dataset.setColors(listColor);
    dataset.setCircleColor(positifColor);
    dataset.setCircleRadius(1.5f);
    dataset.setCircleColorHole(positifColor);
    //dataset.setDrawCircles(false);
    LineData data = new LineData(dataset);
    return data;
}

private BarData generateBarData() {
    entriesBar = new ArrayList<>();
    positifColor = getResources().getColor(R.color.colorGradient2);
    negatifColor = getResources().getColor(R.color.graphBodyColor);
    for (ChartModel chartModel : chartModels) {
        entriesBar.add(chartModel.getBarEntry());
    }
    final ArrayList<Integer> listColor = new ArrayList<>();
    for (BarEntry barEntry : entriesBar) {
        listColor.add(barEntry.getY() < 0 ? negatifColor : positifColor);
    }
    BarDataSet dataset = new BarDataSet(entriesBar, "label");
    dataset.setDrawValues(false);
    dataset.setColors(positifColor);

    BarData data = new BarData(dataset);
    data.setBarWidth(0.4f);
    this.setDescription(null);
    this.getLegend().setEnabled(false);
    this.setTouchEnabled(false);
    this.setScaleEnabled(false);
    this.animateXY(1000, 1000);

    Paint paint = this.getRenderer().getPaintRender();
    int height = 200;
    LinearGradient linGrad = new LinearGradient(0, 0, 0, height,
            getResources().getColor(R.color.colorRedGradient),
            getResources().getColor(R.color.colorGradient2),
            Shader.TileMode.CLAMP);
    paint.setShader(linGrad);
    this.invalidate();
    return data;
}

}

krishnamurthy12 commented 5 years ago

I am trying to draw dynamic line graph , where i will get temperature value from sensor , I need to draw time vs temperature graph . I have stuck in formatting x axis .

This method giving me the solution upto some extent while inserting value i am using

 Calendar c = Calendar.getInstance();
            SimpleDateFormat dateformat = new SimpleDateFormat("HHmm");
            String hoursMins= dateformat.format(c.getTime());

 setData(hoursmins,temperatureValue);
 xAxis.setValueFormatter(new IAxisValueFormatter() {

             private DecimalFormat mFormat= new DecimalFormat("#0.00");

            @Override
            public String getFormattedValue(float value, AxisBase axis) {
                value= (float) value/100;  //This is to splitup hours and minutes as it is combined 4 digit integer
                return mFormat.format(value);
}

But the issue i am facing here is , as i am using DecimalFormat , the X-axis is taking values from 0.1 to 0.9 But i wil get time only up to 0.60 (which means 60 minutes) from 0.60 to 0.90 nothing will be plotted and that wont look good as gap between the hours. I have tried many solutions but none of those gave me the solution i wanted. Anyone please help me out to solve this.

dongorias commented 5 years ago

it is possible to have 24 points on the abscissa?

CG-Vivek commented 5 years ago

Hi Arias yes you can have multiple points on the abscissa.

On Sun, Apr 21, 2019 at 9:38 PM Don Arias notifications@github.com wrote:

it is possible to have 24 points on the abscissa?

โ€” You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/PhilJay/MPAndroidChart/issues/789#issuecomment-485263296, or mute the thread https://github.com/notifications/unsubscribe-auth/AIQRBMOGXFLCMR54DH5KTALPRSGQ5ANCNFSM4BJA52LQ .

dongorias commented 5 years ago

@CG-Vivek Ok thank you very much for your answer, I explain what I want to do but I do not know how to take to do that. I want to display the graphs by setting the hours of the day, but also in the last 7 days of the week and also the last 30 days

dongorias commented 5 years ago

@CG-Vivek basically the user of my graph will have the choice to see the evolution of graph during the day, but also of the week, and also the month always with the same data

CG-Vivek commented 5 years ago

@DonGorias229 yes you can do this using MPCharts, i don't find any complexity what you want from me?

dongorias commented 5 years ago

@CG-Vivek yes exactly I can do for a day but I do not know how to do it for the last 7 days and the last 30 days, can you help me? find attached a catch for that of the day WhatsApp Image 2019-04-22 at 08 50 14

CG-Vivek commented 5 years ago

@DonGorias229 sure can help you, if it's about iOS development.

dongorias commented 5 years ago

I think that the formatting logic will be the same in Android as in iOS, explain me how to do in iOS that can help me in something

CG-Vivek commented 5 years ago

@DonGorias229 If you have control over data and can filter day/week/month data in iOS i just provide formatted data to xAixs LineChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values:xaxisData)