How to plot MULTIPLE LineSeries on an OxyPlot chart?
This is how I've created multi lines on an OxyPlot chart before, the key is creating a set of DataPoints for each series - called circlePoints & linePoints in the following example code, these are then bound to the CircleSeries and LineSeries:
var xAxis = new DateTimeAxis
{
Position = AxisPosition.Bottom,
StringFormat = Constants.MarketData.DisplayDateFormat,
Title = "End of Day",
IntervalLength = 75,
MinorIntervalType = DateTimeIntervalType.Days,
IntervalType = DateTimeIntervalType.Days,
MajorGridlineStyle = LineStyle.Solid,
MinorGridlineStyle = LineStyle.None,
};
var yAxis = new LinearAxis
{
Position = AxisPosition.Left,
Title = "Value",
MajorGridlineStyle = LineStyle.Solid,
MinorGridlineStyle = LineStyle.None
};
var plot = new PlotModel();
plot.Axes.Add(xAxis);
plot.Axes.Add(yAxis);
var circlePoints = new[]
{
new ScatterPoint(DateTimeAxis.ToDouble(date1), value1),
new ScatterPoint(DateTimeAxis.ToDouble(date2), value2),
};
var circleSeries = new ScatterSeries
{
MarkerSize = 7,
MarkerType = MarkerType.Circle,
ItemsSource = circlePoints
};
var linePoints = new[]
{
new DataPoint(DateTimeAxis.ToDouble(date1), value1),
new DataPoint(DateTimeAxis.ToDouble(date2), value2),
};
var lineSeries = new LineSeries
{
StrokeThickness = 2,
Color = LineDataPointColor,
ItemsSource = linePoints
};
plot.Series.Add(circleSeries);
plot.Series.Add(lineSeries);
Here is how you can achieve a similar result in XAML especially if you are using the MVVM approach.
ViewModel:
public ObservableCollection<DataPoint> DataPointList1 {get;set;}
public ObservableCollection<DataPoint> DataPointList2 {get;set;}
public ObservableCollection<DataPoint> DataPointList3 {get;set;}
public ObservableCollection<DataPoint> DataPointList4 {get;set;}
Using a for loop like below populates DataPointList1 to DataPointList4 with the appropriate datasets.
for (int i = 0; i < dataList.Count; i++)
{
DataPointList1 .Add(new DataPoint{dataList[i].XValue,dataList[i].YValue });
}
XAML:
xmlns:oxy="http://oxyplot.org/wpf"
<oxy:Plot LegendPlacement="Outside" LegendPosition="RightMiddle" Title="Your Chart Title" >
<oxy:Plot.Axes>
<oxy:LinearAxis Title="Your X-axis Title" Position="Bottom" IsZoomEnabled="True" />
<oxy:LinearAxis Title="Your Y-axis Title" Position="Left" IsZoomEnabled="True" />
</oxy:Plot.Axes>
<oxy:Plot.Series>
<oxy:LineSeries Title="Plot1" Color="Black" ItemsSource="{Binding DataPointList1 }"/>
<oxy:LineSeries Title="Plot2" Color="Green" ItemsSource="{Binding DataPointList2 }"/>
<oxy:LineSeries Title="Plot3" Color="Blue" ItemsSource="{Binding DataPointList3 }"/>
<oxy:LineSeries Title="Plot4" Color="Red" ItemsSource="{Binding DataPointList4 }"/>
</oxy:Plot.Series>
</oxy:Plot>
Sucess!!!!
AwkwardCoder, thank you for the help, but I realized my mistake was just me having overlooked some things!
Here is the version of the code that works:
// Make a new plotmodel
private PlotModel model = new PlotModel();
// Create the OxyPlot graph for Salt Split
private OxyPlot.Wpf.PlotView plot = new OxyPlot.Wpf.PlotView();
// Function to plot data
private void plotData(double numWeeks, double startingSS)
{
List<LineSeries> listPointAray = new List<LineSeries>();
// Initialize new Salt Split class for acess to data variables
Salt_Split_Builder calcSS = new Salt_Split_Builder();
calcSS.compute(numWeeks, startingSS, maxDegSS);
// Create new Line Series
LineSeries linePoints = new LineSeries()
{ StrokeThickness = 1, MarkerSize = 1, Title = numWeeks.ToString() + " weeks" };
// Add each point to the new series
foreach (var point in calcSS.saltSplitCurve)
{
DataPoint XYpoint = new DataPoint();
XYpoint = new DataPoint(point.Key, point.Value * 100);
linePoints.Format("%", XYpoint.Y);
linePoints.Points.Add(XYpoint);
}
listPointAray.Add(linePoints);
// Add Chart Title
model.Title = "Salt Split Degradation";
// Add Each series to the
foreach (var series in listPointAray)
{
// Define X-Axis
OxyPlot.Axes.LinearAxis Xaxis = new OxyPlot.Axes.LinearAxis();
Xaxis.Maximum = numWeeks;
Xaxis.Minimum = 0;
Xaxis.Position = OxyPlot.Axes.AxisPosition.Bottom;
Xaxis.Title = "Number of Weeks";
model.Axes.Add(Xaxis);
//Define Y-Axis
OxyPlot.Axes.LinearAxis Yaxis = new OxyPlot.Axes.LinearAxis();
Yaxis.MajorStep = 15;
Yaxis.Maximum = calcSS.saltSplitCurve.Last().Value * 100;
Yaxis.MaximumPadding = 0;
Yaxis.Minimum = 0;
Yaxis.MinimumPadding = 0;
Yaxis.MinorStep = 5;
Yaxis.Title = "Percent Degradation";
//Yaxis.StringFormat = "{0.00} %";
model.Axes.Add(Yaxis);
model.Series.Add(series);
}
// Add the plot to the window
plot.Model = model;
plot.InvalidatePlot(true);
SaltSplitChartGrid.Children.Clear();
SaltSplitChartGrid.Children.Add(plot);
}
Here are the multiple things I did wrong:
- In my foreach var series loop, I was adding the original series which had already been added and NOT the next var series in the list! (dumb!)
- I was creating a new model each time I ran the method. This means that each time the code ran, I was adding a series that already existed in the previous model. (also dumb!)
- I was creating a new plot every time and trying to add a model in the new plot that already belonged to a previous plot. (getting dummer..)
- The plot was being added to the grid each time I ran the method, so I had to CLEAR the grid's children first before re-adding the same plot.
- I was not refreshing the plot.
That was a lot of mistakes, but I worked through it. Hopefully this helps someone in the future. Also, I know I am not using ordinary data binding techniques, but this, at-least, works.
Final result: