LiveCharts - 连接缺失点

LiveCharts - Connect across missing points

我正在使用 LiveCharts 在同一张图上绘制多个折线图。一些图表缺少数据点。

当前图表有差距:

我想跨越这些鸿沟:

可能的话目标:

MainWindow.xaml

<Window x:Class="LiveChartsTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <lvc:CartesianChart Series="{Binding Series}">
            <lvc:CartesianChart.AxisX>
                <lvc:Axis Title="Date" Labels="{Binding Labels}"/>
            </lvc:CartesianChart.AxisX>
        </lvc:CartesianChart>
    </Grid>
</Window>

MainWindow.xaml.cs

using LiveCharts;
using LiveCharts.Wpf;
using System;
using System.Windows;

namespace LiveChartsTest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            // Create date labels
            Labels = new string[10];
            for (int i = 0; i < Labels.Length; i++)
            {
                Labels[i] = DateTime.Now.Add(TimeSpan.FromDays(i)).ToString("dd MMM yyyy");
            }

            Series = new SeriesCollection
                {
                    new LineSeries
                    {
                        Title = "Dataset 1",
                        Values = new ChartValues<double>
                        {
                            4,
                            5,
                            7,
                            double.NaN,
                            double.NaN,
                            5,
                            2,
                            8,
                            double.NaN,
                            6
                        }
                    }, 
                    new LineSeries
                    {
                        Title = "Dataset 2",
                        Values = new ChartValues<double>
                        {
                            2,
                            3,
                            4,
                            5,
                            6,
                            3,
                            1,
                            4,
                            5,
                            3
                        }
                    }
                };

            DataContext = this;
        }

        public SeriesCollection Series { get; set; }
        public string[] Labels { get; set; }


    }
}

有没有办法用 LiveCharts 做到这一点?

这看起来更像是一个数学三角问题,你必须计算出缺失点的坐标并将它们添加到 SeriesCollection 这样你就可以在碎片之间得到平坦的环缝。

根据你的图表考虑以下解释性图片:

XY之间我们必须推导出两点,AB(我们知道中间需要两个,因为我们可以从 XY[=78= 之间的间隔推导出来] 或者我们可以简单地计算初始集合中的 NaNs)。 A & B Y 坐标可以使用我们已知的知识和角度 α 轻松推导出来。 我们正在计算 |BB'||AA'| 大小(添加到 y 并且索引应该代表最终的 AB)

我们基本知道:tan(α)= |BB'|/|B'Y| = |AA'|/|A'Y| = |XZ|/|ZY|

为简单起见,现在假设X轴Y轴的所有区间都等于1,我会回来的稍后再说。

现在我们知道 |XZ|/|ZY|, (xz 是x和y的差,zy基本上就是中间有多少NaN),所以我们很容易计算出|BB'||AA'|:

  • |BB'| = (|XZ|/|ZY|) * |B'Y|(注意 |B'Y| 等于一,因为它是一个单位间隔)
  • |AA'| = (|XZ|/|ZY|) * |A'Y| (注意 |A'Y| 等于二元区间)

这里是上面解释的基本实现方式(代码应该是不言自明的):

public partial class MainWindow : Window
{

    public MainWindow()
    {
        InitializeComponent();
        // Create date labels
        Labels = new string[10];
        for (int i = 0; i < Labels.Length; i++)
        {
            Labels[i] = DateTime.Now.Add(TimeSpan.FromDays(i)).ToString("dd MMM yyyy");
        }

        var chartValues = new ChartValues<double>
        {
            4,
            5,
            7,
            double.NaN,
            double.NaN,
            5,
            2,
            8,
            double.NaN,
            6
        };
        Series = new SeriesCollection
        {
            new LineSeries
            {
                Title = "Dataset 1",
                Values = ProcessChartValues(chartValues)
            },
            new LineSeries
            {
                Title = "Dataset 2",
                Values = new ChartValues<double>
                {
                    2,
                    3,
                    4,
                    5,
                    6,
                    3,
                    1,
                    4,
                    5,
                    3
                }
            }
        };

        DataContext = this;
    }

    private ChartValues<double> ProcessChartValues(ChartValues<double> chartValues)
    {
        var tmpChartValues = new ChartValues<double>();
        double bornLeft =0, bornRight=0;
        double xz = 0, zy = 0, xy = 0;
        bool gapFound = false;
        foreach (var point in chartValues)
        {
            if (!double.IsNaN(point))
            {
                if (gapFound)
                {
                    // a gap was found and it needs filling 
                    bornRight = point;
                    xz = Math.Abs(bornLeft - bornRight);
                    for (double i = zy; i >0; i--)
                    {
                        tmpChartValues.Add((xz / zy) * i + Math.Min(bornLeft, bornRight));
                    }

                    tmpChartValues.Add(point);
                    gapFound = false;
                    zy = 0;
                }
                else
                {
                    tmpChartValues.Add(point);
                    bornLeft = point;
                }
            }
            else if(gapFound)
            {
                zy += 1;
            }
            else
            {
                zy += 1;
                gapFound = true;
            }
        }
        return tmpChartValues;
    }

    public SeriesCollection Series { get; set; }
    public string[] Labels { get; set; }
}

这里输出:

现在回到我们的区间大小,请注意由于我们的 interval=1 假设,片段并不清晰,但另一方面,这个假设给出了图表一些平滑度很可能是任何人都会追求的。如果您仍然需要尖锐的碎片,您可以探索 LiveChart API 以获得我不确定它们提供的以像素为单位的间隔(然后简单地乘以 xzzy 大小)否则你可以从图表绘制区域的 ActualWidthActualHight 中推断出来。

最后一点,应该扩展代码以处理边缘上的 NaN 点(您必须忽略它们或定义图形应该走向的方向)。