6
votes

When setting up an OxyPlot plot view, you can either define the plot explicitly through various controls, or set it up through a binding to a PlotModel.

As such, in the first case, the XAML for a plot of two LineSeries objects could look something like

<oxy:Plot Title="Some plot">
    <oxy:Plot.Axes>
        <oxy:LinearAxis Position="Left" />
        <oxy:LinearAxis Position="Bottom" />
    </oxy:Plot.Axes>
    <oxy:Plot.Series>
        <oxy:LineSeries ItemsSource="{Binding ActualSeriesData1}" DataFieldX="X" DataFieldY="Y"/>
        <oxy:LineSeries ItemsSource="{Binding ActualSeriesData2}" DataFieldX="X" DataFieldY="Y"/>
    </oxy:Plot.Series>
</oxy:Plot>

with a very thin view-model. On the other hand, in the second case, I would simply have something like

<oxy:PlotView Model="{Binding SomePlotModel}" />

and construct the actual plot in the view-model. There are pros and cons to both setups, but I find that the first approach generally works better when I know beforehand what I actually want to plot, whereas the second approach allows for dynamic changes to the plot contents.

My issue is the following: For the first case I know how to add general styling to all plots. If, for instance, I want them to make them look Seaborn-like, I would just add something like

<x:Array Type="Color" x:Key="SeabornColors">
    <Color>#4c72b0</Color>
    <Color>#55a868</Color>
    <Color>#c44e52</Color>
    <Color>#8172b2</Color>
    <Color>#ccb974</Color>
    <Color>#64b5cd</Color>
</x:Array>
<Style TargetType="oxy:Plot">
    <Setter Property="PlotAreaBackground" Value="#EBEBF2" />
    <Setter Property="PlotAreaBorderThickness" Value="0" />
    <Setter Property="TitleFont" Value="Segoe UI" />
    <Setter Property="TitleFontWeight" Value="Normal" />
    <Setter Property="DefaultColors" Value="{StaticResource SeabornColors}"/>
</Style>
<Style TargetType="oxy:LinearAxis">
    <Setter Property="TicklineColor" Value="White" />
    <Setter Property="MajorGridlineColor" Value="White" />
    <Setter Property="MinorGridlineColor" Value="White" />
    <Setter Property="ExtraGridlineColor" Value="White" />
    <Setter Property="AxislineColor" Value="White" />
    <Setter Property="TitleColor" Value="Black" />
    <Setter Property="TextColor" Value="Black" />
    <Setter Property="Font" Value="Segoe UI" />
    <Setter Property="TitleFont" Value="Segoe UI" />
    <Setter Property="TickStyle" Value="None" />
    <Setter Property="MajorGridlineStyle" Value="Solid" />
</Style>

to my ResourceDictionary. How can I achieve the same effect in the second case, i.e. using an oxy:PlotView? I can set some of the general styling properties using a <Style TargetType="oxy:PlotView" />, but how would I style, say, all LineSeries contained within a Series within a Model within a PlotView?

1
I've had the same problem, and the only way I was able to solve it is by using code behind to set the properties on the PlotModels. It still separates the design from the logic, but unfortunately not using XAML or styles. - Herman
@Herman: Is there a straightforward way of doing that so that it works for all PlotModels in the application? That's one of the nice things about just setting it in a style. - fuglede
The best way I could come up with is creating a method for each style that takes a PlotModel as argument, then iterate over all plot models and call the method for each PlotModel. Theoretically, you could find all PlotViews in a Window and extract the PlotModel but in my case my ViewModel already has an array of the plot models so that is simpler. - Herman
I think your question is not specific enough. Whenever using a PlotView / PlotModel / Plot, nothing is ever stopping you from re-using your XAML resources, either as a StaticResource or through Application.Current.Resources["SomeResourceKey"] in code-behind. Bear in mind though, that there might be incompatible types, for instance, between Color and OxyColor. And also between OxyPlot.Wpf.LinearAxis and OxyPlot.Axes.LinearAxis ...... - jsanalytics
@RobL Depends on the type of project; since this one was about WPF in particular, we'd do xmlns:oxy="clr-namespace:OxyPlot.Wpf;assembly=OxyPlot.Wpf". I don't know what the relevant types are called in Xamarin.Forms, but if it doesn't have a Plot, I guess you'd just use whatever you use in Xamarin.Forms instead. - fuglede

1 Answers

0
votes

I didn't get through all the comments but some of them seems to already contain links to the solution. I have an example where I'm using MVVM approach and changing those setting. It should help:

In MainWindow.xaml:

<oxy:PlotView Name="TestView" Model="{Binding plotModel}" Grid.Row="0" Grid.Column="1" />

In my MainWindowViewModel.cs:

private PlotModel m_plotModel;
public PlotModel plotModel
{
    get { return m_plotModel; }
    set => SetAndRaisePropertyChanged(ref m_plotModel, value);
}

public UserControlOscilloViewModel()
{
    var signalAxis = new CategoryAxis()
    {
        Position = AxisPosition.Left,
        Minimum = 0,
        MinimumMinorStep = 1,
        AbsoluteMinimum = 0,
        TicklineColor = OxyColors.Transparent,
    };
    var timeAxis = new LinearAxis()
    {
        Position = AxisPosition.Bottom,
        Minimum = 0,
        MinimumMajorStep = 1,
        AbsoluteMinimum = 0,
    };

    plotModel = new PlotModel();            
    plotModel.Axes.Add(signalAxis);
    plotModel.Axes.Add(timeAxis);
}

Then when you are refreshing your model, you can access your axis like this if needed:

CategoryAxis signalAxis = (CategoryAxis)plotModel.Axes.ElementAt(0);
LinearAxis timeAxis = (LinearAxis)plotModel.Axes.ElementAt(1);

and add series like this:

var series = new LineSeries
{
    Color = OxyColors.SeaShell,
    LineStyle = LineStyle.Dash
};
foreach (DataPoint p in ListOfPoints)
{
    series.Points.Add(p);
}
plotModel.Series.Add(series);
plotModel.InvalidatePlot(true);

I'm not addressing exactly what you asked, but I think you have access to all needed objects/members by doing this. I also simplified my code to improve clarity, I hope I didn't break anything when doing so...