c# wpf graph oxyplot

c# - Cómo actualizar el gráfico de oxyplot cuando los datos cambian



wpf graph (7)

Oxyplot grafica 13 puntos que se derivan de los 6 cuadros de texto de entrada del usuario. Los valores en los cuadros de texto se mantienen en variables públicas en la clase MainWindow.xaml.cs. Las variables se actualizan cuando el usuario presiona entrar en el cuadro de texto. ¿Cómo haría que el botón de actualización actualice el gráfico?

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

Creo que esto se haría usando el

PlotModel.RefreshPlot()

método, pero no estoy seguro de cómo implementarlo debido a la mala documentación de Oxyplot.


Acabo de actualizar a una nueva versión de OxyPlot a través de NuGet. Estoy usando OxyPlot.Wpf v20014.1.277.1 y creo que ahora necesitas llamar a InvalidatePlot(bool updateData) en PlotModel lugar de RefreshPlot (que ya no está disponible). Probé esto en mi código de muestra y funcionó como se esperaba.

Si desea actualizar el gráfico y actualizar las recopilaciones de datos, debe pasarle true a la llamada:

PlotModel.InvalidatePlot(true)


x:Name a la instancia de OxyPlot en XAML:

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

y en el botón de hacer clic en el controlador, actualice así:

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


Después de tener la misma pregunta con el mismo problema, parece que la única solución que funciona (al menos desde mi punto de vista) es la siguiente:

PlotView.InvalidatePlot(true)

Al hacerlo, después de actualizar una o varias Series , actualice su PlotView .

La frecuencia de actualización depende de la frecuencia o la frecuencia con la que se actualizan las series.

Aquí hay un fragmento de código (en Xamarin Android, pero debería funcionar de todos modos):

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;

Ahora, cuando necesite agregar DataPoints a su LineSerie y actualizar automáticamente PlotView consecuencia, haga lo siguiente:

resultsChart.InvalidatePlot(true);

Al hacerlo, se actualizará automáticamente su PlotView .

En una nota al PlotView , el PlotView también se actualizará cuando ocurra un evento como un toque, un pellizco para acercar o cualquier tipo de eventos relacionados con la IU.

Espero poder ayudar. Tuve problemas con esto durante mucho tiempo.


Dos años más tarde ... esta solución funciona para mí, porque no tengo modelos de oxyplot y me faltan algunas de las funciones nombradas de arriba.

código detrás:

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); } }

Para actualizar sus datos , no intercambie la lista completa, agregue algunos DataPoints nuevos y elimine los antiguos en la posición 0.

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>

importantes son x: Name = "myChart" y ItemsSource = "{Binding Points}"

Espero que esto sea útil para alguien por ahí


En el actual OxyPlot.Wpf (1.0.0-unstable1983) tiene dos opciones:

  1. Series.ItemsSource propiedad Series.ItemsSource de XAML a una colección en su modelo de vista e intercambie toda la colección cuando necesite una actualización. Esto también permite actualizaciones asíncronas concurrentes con conjuntos de datos más grandes.
  2. Plot.InvalidateFlag propiedad Plot.InvalidateFlag de tipo int a su modelo de vista e incremente cada vez que necesite una actualización. Sin embargo, no he probado este enfoque.

El siguiente código ilustra ambas opciones (elija una). XAML:

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

Actualizaciones en el 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++; }


Existen tres alternativas para actualizar el gráfico (de la documentación de OxyPlot ):

  • Cambiar la propiedad Model del control PlotView
  • Llamada PlotView en el control PlotView
  • Call Invalidate en PlotModel

La forma más limpia que he encontrado para obtener "una especie de actualización automática" es reaccionar a CollectionChanged en la colección que es ItemsSource de LineSeries.

En 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);