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
这样你就可以在碎片之间得到平坦的环缝。
根据你的图表考虑以下解释性图片:
在X和Y之间我们必须推导出两点,A和B(我们知道中间需要两个,因为我们可以从 X 和 Y[=78= 之间的间隔推导出来] 或者我们可以简单地计算初始集合中的 NaN
s)。
A & B Y 坐标可以使用我们已知的知识和角度 α 轻松推导出来。
我们正在计算 |BB'| 和 |AA'| 大小(添加到 y 并且索引应该代表最终的 A 和 B)
我们基本知道: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 以获得我不确定它们提供的以像素为单位的间隔(然后简单地乘以 xz 和 zy 大小)否则你可以从图表绘制区域的 ActualWidth
和 ActualHight
中推断出来。
最后一点,应该扩展代码以处理边缘上的 NaN
点(您必须忽略它们或定义图形应该走向的方向)。
我正在使用 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
这样你就可以在碎片之间得到平坦的环缝。
根据你的图表考虑以下解释性图片:
在X和Y之间我们必须推导出两点,A和B(我们知道中间需要两个,因为我们可以从 X 和 Y[=78= 之间的间隔推导出来] 或者我们可以简单地计算初始集合中的 NaN
s)。
A & B Y 坐标可以使用我们已知的知识和角度 α 轻松推导出来。
我们正在计算 |BB'| 和 |AA'| 大小(添加到 y 并且索引应该代表最终的 A 和 B)
我们基本知道: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 以获得我不确定它们提供的以像素为单位的间隔(然后简单地乘以 xz 和 zy 大小)否则你可以从图表绘制区域的 ActualWidth
和 ActualHight
中推断出来。
最后一点,应该扩展代码以处理边缘上的 NaN
点(您必须忽略它们或定义图形应该走向的方向)。