I'm trying to write a WPF application to plot line charts for series of numbers I have. These numbers are listed in a .CSV
file which I will read at run time. Thus, I do not know the number of series I will have, nor the max/min values of each.
To demonstrate, and for the sake of brevity, take a look at the following example. Think of these series values as what I will read from my .CSV
file in my actual application.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
SeriesCollection = new SeriesCollection
{
new LineSeries
{
Title = "Series 1",
Values = new ChartValues<double> { 4, 66, 5, 2, 4 },
},
new LineSeries
{
Title = "Series 2",
Values = new ChartValues<double> { 6, 7, 3, 4, 6 },
},
new LineSeries
{
Title = "Series 3",
Values = new ChartValues<double> { 4, 2, 7, 2, 7 },
}
};
DataContext = this;
}
public SeriesCollection SeriesCollection { get; set; }
}
My XAML
looks very simple, like so:
<Window x:Class="WPFCharts.MainWindow"
...
Title="MainWindow" Height="450" Width="800">
<Grid>
<lvc:CartesianChart Series="{Binding SeriesCollection}"/>
</Grid>
</Window>
As you can see, one of the values in one series is off the charts compared to the rest if I were to plot this in a line graph with default LiveCharts
settings:
So I want to give the user the opportunity to put such line graphs in their own axis. Reading through LiveCharts
documentation, I found, as shown here, that you can put different line series in different axis by using the ScaleXAt
and ScaleYAt
properties.
However that example sets axis in XAML
whereas I want to do this dynamically. So I tried setting the said property in code behind like so:
SeriesCollection = new SeriesCollection
{
new LineSeries
{
Title = "Series 1",
Values = new ChartValues<double> { 4, 66, 5, 2, 4 },
ScalesYAt = 0
},
new LineSeries
{
Title = "Series 2",
Values = new ChartValues<double> { 6, 7, 3, 4, 6 },
ScalesYAt = 1
},
new LineSeries
{
Title = "Series 3",
Values = new ChartValues<double> { 4, 2, 7, 2, 7 },
ScalesYAt = 2
}
};
But when I do that, and run the application, I get an exception saying:
System.ArgumentOutOfRangeException: 'Index was out of range. Must be non-negative and less than the size of the collection.'
What am I doing wrong here? How can I set this using code, not XAML
?
If you want to use different Y Axis, then you need to declare them, maybe you missed it. So your model will become something like:
public class ViewModel
{
public ViewModel()
{
SeriesCollection = new SeriesCollection
{
new LineSeries
{
Title = "Series 1",
Values = new ChartValues<double> { 4, 66, 5, 2, 4 },
ScalesYAt = 0
},
new LineSeries
{
Title = "Series 2",
Values = new ChartValues<double> { 6, 7, 3, 4, 6 },
ScalesYAt = 1
},
new LineSeries
{
Title = "Series 3",
Values = new ChartValues<double> { 4, 2, 7, 2, 7 },
ScalesYAt = 2
}
};
AxisYCollection = new AxesCollection
{
new Axis { Title = "Y Axis 1", Foreground = Brushes.Gray },
new Axis { Title = "Y Axis 2", Foreground = Brushes.Red },
new Axis { Title = "Y Axis 3", Foreground = Brushes.Brown }
};
}
public AxesCollection AxisYCollection { get; set; }
public SeriesCollection SeriesCollection { get; set; }
}
while the XAML will be:
<Grid>
<lvc:CartesianChart Series="{Binding SeriesCollection}" AxisY="{Binding AxisYCollection}" />
</Grid>
Of course you need to set an instance of ViewModel
class as the DataContext
of your Window:
public MainWindow()
{
vm = new ViewModel();
InitializeComponent();
DataContext = vm;
}
If you do not declare "enough" Axis in the binded AxesCollection
, its element at n index won't be found and you will slip into an ArgumentOutOfRangeException. I hope it can help you.