用值和日期制作折线图

Make line chart with values and dates

在我的应用程序中,我使用 ios-图表库(swift 替代 MPAndroidChart)。 我只需要显示带有日期和值的折线图。

现在我用这个功能来显示图表

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      
}

这是我的数据:

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

但如您所见 - xItems 是 "dd.mm" 格式的日期。因为它们是字符串,所以它们彼此之间有相同的填充。我希望他们在真实日期上更准确。例如 19.09 和 20.09 应该非常接近。我知道我应该每天匹配一些数字才能完成它。但我不知道下一步该怎么做 - 如何调整 x 标签边距?

更新 经过小型研究后,我发现许多开发人员都询问过此功能但没有任何反应 - 就我而言,我在 Swift - PNChart 中找到了这个库的非常有趣的替代方案。简单易用,解决了我的问题。

最简单的解决方案是遍历您的数据并添加值为 0 的 ChartDataEntry 和每个缺失日期的相应标签。

为了回答评论中的问题,这里是我的一个应用程序的屏幕截图,我在其中用 0 值填充日期空白:

在我的例子中,我想要 0 值而不是从数据点到数据点的平均线,因为它清楚地表明在跳过的日子里没有数据(例如 8/11)。

根据@Philipp Jahoda 的评论,听起来您可以跳过 0 值条目,只需将您拥有的数据索引到正确的标签即可。

我修改了 MPAndroidChart 示例程序以跳过几个数据点,结果如下:

正如@Philipp Jahoda 在评论中提到的那样,图表通过连接到下一个数据点来处理丢失的 Entry。从下面的代码中,您可以看到我正在为整个数据集生成 x 值(标签),但跳过索引 11 - 29 的 y 值(数据点),这正是您想要的。剩下的唯一事情就是处理 x 标签,因为听起来您不希望我的示例中的 15、20 和 25 出现。

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));
}

我所做的是完全为 x 数据提供日期,甚至没有为它提供 y 数据,并且只是不添加特定 xIndex 的数据条目,然后它不会绘制 xIndex 的 y 值来实现你的目标想要,这是最简单的方法,因为您只需编写一个 for 循环,如果您在那里没有检测到 y 值,则继续。

我不建议使用0或nan,因为如果是折线图,它会连接0数据,否则nan会发生不好的事情。你可能想要换行,但是 ios-charts 还不支持它(我也为此询问了一个功能),你需要编写自己的代码来换行,或者你可以接受连接0 数据或仅连接到下一个有效数据。

缺点是性能可能会下降,因为那里有很多 xIndex,但我尝试了 ~1000,这是可以接受的。很久以前我就要求过这样的功能,但是考虑了很多时间。

对我有用的解决方案是将线数据集拆分为 2 个线数据集。首先将 yvals 保持到空 space,然后在空 space.

之后保持第二个
//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);

这是我根据 Wingzero 的回答编写的一个函数(我为值数组中为空的条目传递了 NaN):

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
}