2

In my app i use ios-charts library (swift alternative of MPAndroidChart). All i need is to display line chart with dates and values.

Right now i use this function to display chart

func setChart(dataPoints: [String], values: [Double]) {       

    var dataEntries: [ChartDataEntry] = []

    for i in 0..<dataPoints.count {
        let dataEntry = ChartDataEntry(value: values[i], xIndex: i)
        dataEntries.append(dataEntry)
    }        

    let lineChartDataSet = LineChartDataSet(yVals: dataEntries, label: "Items count")
    let lineChartData = LineChartData(xVals: dataPoints, dataSet: lineChartDataSet)
    dateChartView.data = lineChartData      
}

And this is my data:

xItems = ["27.05", "03.06", "17.07", "19.09", "20.09"] //String    
let unitsSold = [25.0, 30.0, 45.0, 60.0, 20.0] //Double

But as you can see - xItems are dates in "dd.mm" format. As they are strings they have same paddings between each other. I want them to be more accurate with real dates. For example 19.09 and 20.09 should be very close. I know that i should match each day with some number in order to accomplish it. But i don't know what to do next - how i can adjust x labels margins?

UPDATE After small research where i found out that many developers had asked about this feature but nothing happened - for my case i found very interesting alternative to this library in Swift - PNChart. It is easy to use, it solves my problem.

moonvader
  • 19,761
  • 18
  • 67
  • 116

4 Answers4

2

The easiest solution will be to loop through your data and add a ChartDataEntry with a value of 0 and a corresponding label for each missing date.

In response to the question in the comments here is a screenshot from one of my applications where I am filling in date gaps with 0 values:

Chart Gaps

In my case I wanted the 0 values rather than an averaged line from data point to data point as it clearly indicates there is no data on the days skipped (8/11 for instance).

From @Philipp Jahoda's comments it sounds like you could skip the 0 value entries and just index the data you have to the correct labels.

I modified the MPAndroidChart example program to skip a few data points and this is the result:

Chart Gaps Non Zero

As @Philipp Jahoda mentioned in the comments the chart handles missing Entry by just connecting to the next data point. From the code below you can see that I am generating x values (labels) for the entire data set but skipping y values (data points) for index 11 - 29 which is what you want. The only thing remaining would be to handle the x labels as it sounds like you don't want 15, 20, and 25 in my example to show up.

ArrayList<String> xVals = new ArrayList<String>();
for (int i = 0; i < count; i++) {
    xVals.add((i) + "");
}

ArrayList<Entry> yVals = new ArrayList<Entry>();

for (int i = 0; i < count; i++) {

    if (i > 10 && i < 30) {
        continue;
    }

    float mult = (range + 1);
    float val = (float) (Math.random() * mult) + 3;// + (float)
    // ((mult *
    // 0.1) / 10);
    yVals.add(new Entry(val, i));
}
Cory Charlton
  • 8,868
  • 4
  • 48
  • 68
  • How chart would look like in this case? Between all my values there will be lines on 0. If I am right this solution is not for me. – moonvader Nov 10 '15 at 06:02
  • Yes, that is how the chart would look. There would be lines at zero where you filled the gaps. How else would you expect it to look? Or rather how would you like it to look? – Cory Charlton Nov 10 '15 at 06:30
  • You don't necessarily need to have as many x-values as entries. You just need to have enough x-values to cover the highest x-index. So I suggest you just add e.g. the days of a whole year as x-values and then add entries at the correct x-indices. If you have an entry on "jan 1" it e.g. will have x-index 0, if your next entry is on "jan 5", than give it an x-index of 4. All values in between will just be skipped. – Philipp Jahoda Nov 10 '15 at 08:44
  • @CoryCharlton i thought it would be better if there would be only real values on chart without zero lines. For example: it is temperature chart and measurements were made few times a week and temperature was from 10 to 20 degrees - it doesn't mean that in other days it was 0. – moonvader Nov 10 '15 at 14:26
  • @moonvader I added a screenshot showing what the "gap" entries look like and my rationale for using them in my case. – Cory Charlton Nov 10 '15 at 17:51
  • I see that in your case it is ok because there is small gap but imagine that I have about 20 values for 2 years. – moonvader Nov 10 '15 at 18:04
  • Look at this chart https://raw.githubusercontent.com/i-schuetz/SwiftCharts/master/Screenshots/IMG_0038.jpeg – moonvader Nov 10 '15 at 18:45
  • See my updated post. It implements what @Philipp Jahoda mentioned. I assume the only thing missing is that you would like the x labels to only appear where there is a value? – Cory Charlton Nov 10 '15 at 18:59
  • just add "" as the x-label if there is no value – Philipp Jahoda Nov 10 '15 at 20:47
2

What I did is fully feed the dates for x data even no y data for it, and just not add the data entry for the specific xIndex, then it will not draw the y value for the xIndex to achieve what you want, this is the easiest way since you just write a for loop and continue if you detect no y value there.

I don't suggest use 0 or nan, since if it is a line chart, it will connect the 0 data or bad things will happen for nan. You might want to break the lines, but again ios-charts does not support it yet (I also asked a feature for this), you need to write your own code to break the line, or you can live with connecting the 0 data or just connect to the next valid data.

The down side is it may has performance drop since many xIndex there, but I tried ~1000 and it is acceptable. I already asked for such feature a long time ago, but it took lot of time to think about it.

Wingzero
  • 9,644
  • 10
  • 39
  • 80
  • thank you for you answer! I found a lot of requests for this feature with no success, so i start to search for alternatives to this library - and i found PNChart. Will try it. – moonvader Nov 11 '15 at 08:33
1

Here's a function I wrote based on Wingzero's answer (I pass NaNs for the entries in the values array that are empty) :

func populateLineChartView(lineChartView: LineChartView, labels: [String], values: [Float]) {
    var dataEntries: [ChartDataEntry] = []

    for i in 0..<labels.count {
        if !values[i].isNaN {
            let dataEntry = ChartDataEntry(value: Double(values[i]), xIndex: i)
            dataEntries.append(dataEntry)
        }
    }

    let lineChartDataSet = LineChartDataSet(yVals: dataEntries, label: "Label")
    let lineChartData = LineChartData(xVals: labels, dataSet: lineChartDataSet)
    lineChartView.data = lineChartData
}
Carl Smith
  • 1,236
  • 15
  • 18
0

The solution which worked for me is splitting Linedataset into 2 Linedatasets. First would hold yvals till empty space and second after emptyspace.

//create 2 LineDataSets. set1- till empty space set2 after empty space

set1 = new LineDataSet(yVals1, "DataSet 1");
set2= new LineDataSet(yVals2,"DataSet 1");

//load datasets into datasets array 

ArrayList<ILineDataSet> dataSets = new ArrayList<ILineDataSet>();
dataSets.add(set1);
dataSets.add(set2);

//create a data object with the datasets

LineData data = new LineData(xVals, dataSets);

// set data
mChart.setData(data);
Vygintas B
  • 1,624
  • 13
  • 31