WPF Toolkit Chart ScatterSeries не отображает точки данных
У меня есть две диаграммы в моем приложении, я использую System.Windows.Controls.DataVisualization.Toolkit.
Одна диаграмма отображает элементы LineSeries, где каждая новая точка данных добавляется отдельно. Эта диаграмма использует
ObservableCollection<KeyValuePair<int, double>>
модель как ItemsSource. Это работает так же, как и ожидалось. Показывает линии и маркеры.
На другой диаграмме показан график XYPlot с произвольным количеством точек данных, протестированных с 15, 50, 1500 и т. Д. Он использует ScatterSeries для отображения точек данных. Он использует
ObservableCollection<KeyValuePair<double, double>>
модель как ItemsSource.
(Изменить: я начинаю подозревать, что, возможно, моя проблема заключается в том факте, что мои независимые значения X являются значениями с плавающей запятой в случае второго графика, который может не быть поддерживаемым вариантом использования для ScatterSeries - или вообще, для этого типа контроля диаграммы?)
Вторая диаграмма работает (хорошо, более или менее), если я изменяю ScatterSeries на LineSeries, но даже в этом случае отображаются только линии, а не маркеры точек. Почему-то я не могу сделать второй график для отображения маркеров точек.В случае второго графика крайне важно, чтобы я не добавлял баллы по отдельности, а всегда заменял весь ряд новым. Я попытался реализовать класс ObservableCollectionEx, который реализует функцию ReplaceAll и отправляет либо событие NotifyCollectionChangedAction.Replace, либо NotifyCollectionChangedAction.Reset вместе с событием NotifyCollectionChangedAction.Add, но безуспешно. Я пытался обновлять ItemsSource новой коллекцией каждый раз, когда обновляются данные, но все же не повезло.
Все мои приведенные выше попытки, кажется, работают нормально, если я выбираю LineSeries (без отображения маркеров), но когда я хочу видеть только маркеры, используя ScatterSeries, они вообще не отображаются. Я могу видеть диапазон изменения осей, как если бы он правильно следовал за диапазоном данных, но ничего не нарисовано.
Где я могу пойти не так? Являются ли ScatterSeries или вообще маркеры на графике другим способом?
Вот мой график, который работает:
<DVC:Chart Name="errors" Grid.Row="2" Width="auto" Height="auto">
<DVC:Chart.Axes>
<DVC:LinearAxis Orientation="X" FontSize="10" Title="Mean Squared Error"/>
<DVC:LinearAxis Orientation="Y" FontSize="10" ShowGridLines="True"/>
</DVC:Chart.Axes>
<DVC:Chart.LegendStyle>
<Style TargetType="{x:Type DV:Legend}">
<Setter Property="Width" Value="0" />
</Style>
</DVC:Chart.LegendStyle>
<DVC:LineSeries DataContext="{Binding ErrorList}" ItemsSource="{Binding}" IndependentValuePath="Key" DependentValuePath="Value" />
</DVC:Chart>
А вот мой график, который отображает только линии, но не маркеры:
<DVC:Chart Grid.Row="4" x:Name="dataFit" Width="auto" Height="auto">
<DVC:Chart.Axes>
<DVC:LinearAxis Orientation="X" FontSize="10" Title="Regression"/>
<DVC:LinearAxis Orientation="Y" FontSize="10" ShowGridLines="True"/>
</DVC:Chart.Axes>
<DVC:Chart.Series>
<DVC:ScatterSeries Name="scatterPlot" ItemsSource="{Binding DataFitList}" IndependentValueBinding="{Binding Path=Key}" DependentValueBinding="{Binding Path=Value}">
<DVC:ScatterSeries.DataPointStyle>
<Style TargetType="{x:Type DVC:ScatterDataPoint}">
<Setter Property="Visibility" Value="Visible"/>
<Setter Property="Height" Value="10"/>
<Setter Property="Width" Value="10"/>
</Style>
</DVC:ScatterSeries.DataPointStyle>
</DVC:ScatterSeries>
</DVC:Chart.Series>
<DVC:Chart.LegendStyle>
<Style TargetType="{x:Type DV:Legend}">
<Setter Property="Width" Value="0" />
</Style>
</DVC:Chart.LegendStyle>
</DVC:Chart>
Вы можете видеть, что я пытался вручную изменить стиль маркеров, это не имеет никакого эффекта вообще. Когда я изменил его на LineSeries, я смог изменить свойства линий таким же образом.
Я пробовал несколько способов обновить данные. Некоторые фрагменты моих испытаний:
Сначала используйте только привязку, пытаясь заменить все данные в ObservableCollection:
public class ScatterPlotCollection : ObservableCollectionEx<KeyValuePair<double, double>>
{
public ScatterPlotCollection() : base() { }
}
public class ObservableCollectionEx<T> : ObservableCollection<T>
{
public void ReplaceAt(T newElement, int index)
{
CheckReentrancy();
if (index < 0 || index >= Items.Count())
return;
T oldElement = Items[index];
Items[index] = newElement;
this.OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newElement, oldElement, index));
}
public void ReplaceAll(IEnumerable<T> dataToAdd)
{
CheckReentrancy();
int startingIndex = 0;
List<T> oldItems = Items.ToList();
Items.Clear();
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, oldItems, startingIndex));
((List<T>)Items).AddRange(dataToAdd);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, dataToAdd, startingIndex));
}
public void AddRange(IEnumerable<T> dataToAdd)
{
CheckReentrancy();
int startingIndex = this.Count;
foreach (var data in dataToAdd)
{
this.Items.Add(data);
}
this.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
this.OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
var changedItems = new List<T>(dataToAdd);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, changedItems, startingIndex));
}
}
Затем я попробовал метод грубой силы, просто назначая ScatterSeries новый ItemsSource каждый раз, когда я хочу перерисовать его:
((ScatterSeries)dataFit.Series[0]).ItemsSource = tempDataFitList.ToArray();
((ScatterSeries)dataFit.Series[0]).Refresh();
Обе попытки (связывание и изменение ItemsSource), кажется, работают нормально, когда я отображаю LineSeries (без маркеров), ни одна из них, кажется, не работает, когда я отображаю ScatterSeries.
Редактировать: Это пришло мне в голову после сортировки моих мыслей по этому вопросу: возможно ли, что, хотя я использую два отдельных элемента управления Chart в одном и том же окне, они каким-то образом совместно используют общий буфер данных или общий контейнер для данных точки? А может быть, первый график влияет на то, как работает мой второй график?
Что мне не хватает?
(Вот весь проект, нетрудно добраться до точки, где отображаются графики, только для просмотра, если я пропустил упоминание чего-то важного в этом вопросе:
Целое решение: https://github.com/bulyaki/DeepTrainer
Проект WPF: https://github.com/bulyaki/DeepTrainer/tree/master/NNTrainerTesterWPF)