简体   繁体   English

如何在数据更改时刷新oxyplot图

[英]How to refresh oxyplot plot when data changes

该程序的GUI

Oxyplot graphs 13 points which are derived from the 6 user input text boxes. Oxyplot图表13个点,这些点来自6个用户输入文本框。 The values in the text boxes are held in public variables in the MainWindow.xaml.cs class. 文本框中的值保存在MainWindow.xaml.cs类的公共变量中。 The variables are updated when the user presses enter in the text box. 当用户在文本框中按Enter键时,将更新变量。 How would I make the refresh button refresh the graph. 如何使刷新按钮刷新图形。

private void RefreshButton_Click(object sender, RoutedEventArgs e)
        {
            //Refresh The Graph
        }

I think that this would be done using the 我认为这将使用

PlotModel.RefreshPlot() 

method, but I am not sure how to implement it because of Oxyplot's poor documentation. 方法,但我不知道如何实现它,因为Oxyplot的文档很差。

I just updated to a new version of OxyPlot via NuGet. 我刚刚通过NuGet更新到新版本的OxyPlot。 I'm using OxyPlot.Wpf v20014.1.277.1 and I think you now need to call InvalidatePlot(bool updateData) on the PlotModel instead of RefreshPlot (which is no longer available). 我正在使用OxyPlot.Wpf v20014.1.277.1,我认为你现在需要在PlotModel而不是RefreshPlot(不再可用)上调用InvalidatePlot(bool updateData) )。 I tested this in my sample code and it worked as expected. 我在我的示例代码中对此进行了测试,并且按预期工作。

If you want to refresh the plot and update the data collections, you need to pass true to the call: 如果要刷新绘图更新数据集合,则需要将true传递给调用:

PlotModel.InvalidatePlot(true)

Give x:Name to OxyPlot instance in XAML: x:Name为XAML中的OxyPlot实例:

<oxy:Plot x:Name="Plot1"/>

and on button click handler, refresh like this: 并在按钮单击处理程序上,刷新如下:

private void RefreshButton_Click(object sender, RoutedEventArgs e)
{
   Plot1.RefreshPlot(true);
}

The cleanest way I've found to get "sort of" auto-update is reacting to CollectionChanged on the collection that is LineSeries' ItemsSource. 我发现获得“某种”自动更新的最简洁方法是对LineSeries的ItemsSource集合上的CollectionChanged做出反应。

In ViewModel: 在ViewModel中:

ObservableCollection<DataPoint> Data { get; set; } 
    = new ObservableCollection<DataPoint>();

public PlotModel PlotModel
{
    get { return _plot_model; }
    set
    {
        _plot_model = value;
        RaisePropertyChanged(() => PlotModel);
    }
}
PlotModel _plot_model;

// Inside constructor:
Data.CollectionChanged += (a, b) => PlotModel.InvalidatePlot(true);

After having the same question with the same issue, it would seem that the only working solution (at least to my point of view) is as followed : 在对同一问题提出同样的问题之后,似乎唯一可行的解​​决方案(至少在我看来)如下:

PlotView.InvalidatePlot(true)

Doing so, after updating one or multple Series do refresh your PlotView . 这样做,在更新一个或多个Series请刷新PlotView

The refresh rate depends on how often, or at which rate your serie(s) is/are updated. 刷新率取决于您的系列更新的频率或速率。

Here is a code snippet (on Xamarin Android but should work anyway) : 这是一个代码片段(在Xamarin Android上,但无论如何都应该工作):

PlotView resultsChart = FindViewById<PlotView>(Resource.Id.resultsChart);
PlotModel plotModel = new PlotModel
{
    // set here main properties such as the legend, the title, etc. example :
    Title = "My Awesome Real-Time Updated Chart",
    TitleHorizontalAlignment = TitleHorizontalAlignment.CenteredWithinPlotArea,
    LegendTitle = "I am a Legend",
    LegendOrientation = LegendOrientation.Horizontal,
    LegendPlacement = LegendPlacement.Inside,
    LegendPosition = LegendPosition.TopRight
    // there are many other properties you can set here
}

// now let's define X and Y axis for the plot model

LinearAxis xAxis = new LinearAxis();
xAxis.Position = AxisPosition.Bottom;
xAxis.Title = "Time (hours)";

LinearAxis yAxis = new LinearAxis();
yAxis.Position = AxisPosition.Left;
yAxis.Title = "Values";

plotModel.Axes.Add(xAxis);
plotModel.Axes.Add(yAxis);

// Finally let's define a LineSerie

LineSeries lineSerie = new LineSeries
 {
    StrokeThickness = 2,
    CanTrackerInterpolatePoints = false,
    Title =  "Value",
    Smooth = false
  };
plotModel.Series.Add(lineSerie);
resultsChart.Model = plotModel;

Now, whenever you need to add DataPoints to your LineSerie and to updated automatically the PlotView accordingly, just do as followed : 现在,每当您需要将DataPoints添加到LineSerie并相应地自动更新PlotView ,只需执行以下操作:

resultsChart.InvalidatePlot(true);

Doing so will automatically refresh your PlotView . 这样做会自动刷新PlotView

On a side note, the PlotView will also be updated when an event occurs such as a touch, a pinch to zoom, or any kind of UI-related events. 另外,当事件发生时, PlotView也会更新,例如触摸,缩放或任何类型的UI相关事件。

I hope I could help. 我希望我能帮忙。 I had trouble with this for a very long time. 很长一段时间我都遇到了麻烦。

In the current OxyPlot.Wpf (1.0.0-unstable1983) you have two options: 在当前的OxyPlot.Wpf(1.0.0-unstable1983)中,您有两个选择:

  1. Bind the Series.ItemsSource property from XAML to a collection in your viewmodel and exchange the whole collection, when you need an update. Series.ItemsSource属性从XAML绑定到viewmodel中的集合,并在需要更新时交换整个集合。 This also allows for concurrent async updates with larger data sets. 这还允许使用更大的数据集进行并发异步更新。
  2. Bind the Plot.InvalidateFlag property of type int to your viewmodel and increment whenever you need an update. 将类型为intPlot.InvalidateFlag属性绑定到viewmodel,并在需要更新时递增。 I haven't tested this approach, though. 不过,我还没有测试过这种方法。

The following code illustrates both options (pick one). 以下代码说明了这两个选项(选择一个)。 XAML: XAML:

<oxy:Plot InvalidateFlag="{Binding InvalidateFlag}">
    <oxy:Plot.Series>
        <oxy:LineSeries ItemsSource="{Binding DataSeries}" />
      </oxy:Plot.Series>
 </oxy:Plot>

Updates on the ViewModel: ViewModel上的更新:

private async Task UpdateAsync()
{
    // TODO do some heavy computation here
    List<DataPoint> data = await ...

    // option 1: Trigger INotifyPropertyChanged on the ItemsSource.
    //           Concurrent access is ok here.
    this.DataSeries = data; // switch data sets

    // option 2: Update the data in place and trigger via flag
    //           Only one update at a time.
    this.DataSeries.Clear();
    data.ForEach(this.DataSeries.Add);
    this.InvalidateFlag++;
}

Exists three alternatives how refresh plot (from OxyPlot documentation ): 存在三个替代方案如何刷新绘图(来自OxyPlot文档 ):

  • Change the Model property of the PlotView control 更改PlotView控件的Model属性
  • Call Invalidate on the PlotView control PlotView控件上调用Invalidate
  • Call Invalidate on the PlotModel PlotModel上调用Invalidate

Another two years later... this solution works for me, because I have no oxyplot models and I´m missing some of the named functions from above. 再过两年......这个解决方案对我有用,因为我没有氧模型,我错过了上面提到的一些命名函数。

code behind: 代码背后:

public partial class LineChart : UserControl
{
    public LineChart()
    {
        InitializeComponent();

        DataContext = this;
        myChart.Title = "hier könnte Ihr Text stehen!";

        this.Points = new List<DataPoint>();
        randomPoints();
    }


    public IList<DataPoint> Points { get; private set; }

    public void randomPoints()
    {
        Random rd = new Random();
        String myText = "";

        int anz = rd.Next(30, 60);

        for (int i = 0; i < anz; i++)
            myText += i + "," + rd.Next(0, 99) + ";";

        myText = myText.Substring(0, myText.Length - 1);
        String[] splitText = myText.Split(';');

        for (int i = 0; i < splitText.Length; i++)
        {
            String[] tmp = splitText[i].Split(',');
            Points.Add(new DataPoint(Double.Parse(tmp[0].Trim()), Double.Parse(tmp[1].Trim())));
        }

        while (Points.Count > anz)
            Points.RemoveAt(0);

        myChart.InvalidatePlot(true);
    }
}

To update your data don't exchange the whole IList, rather add some new DataPoints to it and remove old ones at position 0. 要更新数据,请不要交换整个IList,而是添加一些新的DataPoints并删除位置0的旧DataPoints。

XAML: XAML:

<UserControl x:Class="UxHMI.LineChart"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:UxHMI"
         xmlns:oxy="http://oxyplot.org/wpf"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid x:Name="Container" Background="White">
    <oxy:Plot x:Name="myChart" Title="{Binding Title}" FontFamily="Bosch Sans Medium" Foreground="#FF0C6596" FontSize="19" Canvas.Left="298" Canvas.Top="32" Background="AliceBlue" Margin="0,0,10,0">
        <oxy:Plot.Series>
            <oxy:LineSeries x:Name="ls" Background="White" ItemsSource="{Binding Points}" LineStyle="Solid" Color="ForestGreen" MarkerType="None" MarkerSize="5" MarkerFill="Black">

            </oxy:LineSeries>
        </oxy:Plot.Series>
    </oxy:Plot>
    <Button x:Name="button" Content="Random" HorizontalAlignment="Left" Margin="0,278,0,0" VerticalAlignment="Top" Width="75" Click="button_Click"/>
</Grid>

important are the x:Name="myChart" and ItemsSource="{Binding Points}" 重要的是x:Name =“myChart”ItemsSource =“{Binding Points}”

I hope this is useful for someone out there 我希望这对那里的人有用

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM