0

Using Oxyplot, how would I remove an item from a given ColumnSeries?

Given the code which is the example provided in the library itself (with a small modification), as well as a Delete event of some sort (which I could figure out myself) how would I remove an item (column) from the graph?

If I simply remove the item from the bar.Items list, the Label won't dissaper. Removing it from the tmp.Axes[0].ActualLabels (which is the CategoryAxis) won't "refresh" the view, and the Label remains there. Is there any solution for this situation? I've managed to do it with Line and Pie Graphs, but I'm struggling with the Column one.

Code-behind for building the Graph:

namespace ColumnSeriesDemo
{
    using System.Collections.ObjectModel;
    using System.Windows;

    using OxyPlot;
    using OxyPlot.Axes;
    using OxyPlot.Series;

    using WpfExamples;

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    [Example("Shows column series.")]
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.InitializeComponent();

            // Create some data
            this.Items = new Collection<Item>
                            {
                                new Item {Label = "Apples", Value1 = 37, Value2 = 12, Value3 = 19},
                                new Item {Label = "Pears", Value1 = 7, Value2 = 21, Value3 = 9},
                                new Item {Label = "Bananas", Value1 = 23, Value2 = 2, Value3 = 29}
                            };

            // Create the plot model
            var tmp = new PlotModel { Title = "Column series", LegendPlacement = LegendPlacement.Outside, LegendPosition = LegendPosition.RightTop, LegendOrientation = LegendOrientation.Vertical };

            // Add the axes, note that MinimumPadding and AbsoluteMinimum should be set on the value axis.
            tmp.Axes.Add(new CategoryAxis { ItemsSource = this.Items, LabelField = "Label" });
            tmp.Axes.Add(new LinearAxis { Position = AxisPosition.Left, MinimumPadding = 0, AbsoluteMinimum = 0 });

            // Add the series, note that the BarSeries are using the same ItemsSource as the CategoryAxis.
            ColumnSeries bar = new ColumnSeries();
            tmp.Series.Add(bar);
            bar.Items.Add(new ColumnItem { Color = OxyPlot.OxyColors.Yellow, Value = this.Items[0].Value3, CategoryIndex = 0 });
            bar.Items.Add(new ColumnItem { Color = OxyPlot.OxyColors.Green, Value = this.Items[0].Value2, CategoryIndex = 2 });
            bar.Items.Add(new ColumnItem { Color = OxyPlot.OxyColors.Red, Value = this.Items[0].Value1, CategoryIndex = 3 });


            this.Model1 = tmp;

            this.DataContext = this;
        }

        public Collection<Item> Items { get; set; }

        public PlotModel Model1 { get; set; }
    }

    public class Item
    {
        public string Label { get; set; }
        public double Value1 { get; set; }
        public double Value2 { get; set; }
        public double Value3 { get; set; }
    }
}
lucas.mdo
  • 339
  • 7
  • 27

1 Answers1

1

I'm not really sure I know what you are trying to do, but I hope this helps you:

I took the Sample and played a little bit around your code and the sample. I think the problem with your code was that you have a Bind in your CategoryAxis, but the data is not added with a Bind but directly in your ColumnSeries. Using your code, I left the first part as it is, and instead of ColumnSeries bar = new ColumnSeries() I did:

        ColumnSeries bar = new ColumnSeries
        {
            FillColor = OxyPlot.OxyColors.Yellow,
            ValueField = "Value1",
            Title = "Value1",
            ItemsSource = Items
        };
        tmp.Series.Add(bar);

This way the data in Items is binded both in your CategoryAxis and in your ColumnSeries (of course if you need more columns representing the Value2 and Value3 values of your Items class you can add new ColumnSeries to the series of your PlotModel)

Then I added a Button to the Window, and in the Code-Behind added:

        Items.RemoveAt(0);
        Model1.InvalidatePlot(true);

And this updates the Plot removing (each time) the first ColumnSeries including the Label in the CategoryAxis.

Window Code-Behind:

using System.Collections.ObjectModel;
using System.Windows;
using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Series;

namespace OxyPlot_TEST
{
    /// <summary>
    /// Interaction logic for Window2.xaml
    /// </summary>
    public partial class Window2 : Window
    {
        public Window2()
        {
            InitializeComponent();

            // Create some data
            this.Items = new Collection<Item>
                            {
                                new Item {Label = "Apples", Value1 = 37, Value2 = 12, Value3 = 19},
                                new Item {Label = "Pears", Value1 = 7, Value2 = 21, Value3 = 9},
                                new Item {Label = "Bananas", Value1 = 23, Value2 = 2, Value3 = 29}
                            };

            // Create the plot model
            var tmp = new PlotModel { Title = "Column series", LegendPlacement = LegendPlacement.Outside, LegendPosition = LegendPosition.RightTop, LegendOrientation = LegendOrientation.Vertical };

            // Add the axes, note that MinimumPadding and AbsoluteMinimum should be set on the value axis.
            tmp.Axes.Add(new CategoryAxis { ItemsSource = this.Items, LabelField = "Label" });
            tmp.Axes.Add(new LinearAxis { Position = AxisPosition.Left, MinimumPadding = 0, AbsoluteMinimum = 0 });

            ColumnSeries bar = new ColumnSeries
            {
                FillColor = OxyPlot.OxyColors.Yellow,
                ValueField = "Value1",
                Title = "Value1",
                ItemsSource = Items
            };
            ColumnSeries bar1 = new ColumnSeries
            {
                FillColor = OxyPlot.OxyColors.Green,
                ValueField = "Value1",
                Title = "Value1",
                ItemsSource = Items
            };
            ColumnSeries bar2 = new ColumnSeries
            {
                FillColor = OxyPlot.OxyColors.Red,
                ValueField = "Value1",
                Title = "Value1",
                ItemsSource = Items
            };
            tmp.Series.Add(bar);
            tmp.Series.Add(bar1);
            tmp.Series.Add(bar2);

            this.Model1 = tmp;
            this.DataContext = this;
        }

        public Collection<Item> Items { get; set; }

        public PlotModel Model1 { get; set; }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            Items.RemoveAt(0);
            Model1.InvalidatePlot(true);
        }
    }

    public class Item
    {
        public string Label { get; set; }
        public double Value1 { get; set; }
        public double Value2 { get; set; }
        public double Value3 { get; set; }
    }
}

<<--------------------------------- EDIT --------------------------------->>

If you just need one bar per category, you need only one Value per Item. Then you can (as in the previous example) Remove or even Add Items from/to the Collection (updating the Plot using InvalidatePlot. Code-Behind:

using System.Collections.ObjectModel;
using System.Windows;
using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Series;

namespace OxyPlot_TEST
{
    /// <summary>
    /// Interaction logic for Window2.xaml
    /// </summary>
    public partial class Window2 : Window
    {
        public Window2()
        {
            InitializeComponent();

            // Create some data
            this.Items = new Collection<Item>
                            {
                                new Item {Label = "Apples", Value1 = 37},
                                new Item {Label = "Pears", Value1 = 7},
                                new Item {Label = "Bananas", Value1 = 23}
                            };

            // Create the plot model
            var tmp = new PlotModel { Title = "Column series", LegendPlacement = LegendPlacement.Outside, LegendPosition = LegendPosition.RightTop, LegendOrientation = LegendOrientation.Vertical };

            // Add the axes, note that MinimumPadding and AbsoluteMinimum should be set on the value axis.
            tmp.Axes.Add(new CategoryAxis { ItemsSource = this.Items, LabelField = "Label" });
            tmp.Axes.Add(new LinearAxis { Position = AxisPosition.Left, MinimumPadding = 0, AbsoluteMinimum = 0 });

            ColumnSeries bar = new ColumnSeries
            {
                FillColor = OxyPlot.OxyColors.Black,
                ValueField = "Value1",
                Title = "Value1",
                ItemsSource = Items
            };
            tmp.Series.Add(bar);

            this.Model1 = tmp;
            this.DataContext = this;
        }

        public Collection<Item> Items { get; set; }

        public PlotModel Model1 { get; set; }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            Items.RemoveAt(0);
            Model1.InvalidatePlot(true);
        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {
            Items.Add(new Item()
            {
                Label = "Strawberrys", Value1 = 55
            });
            Model1.InvalidatePlot(true);
        }
    }

    public class Item
    {
        public string Label { get; set; }
        public double Value1 { get; set; }
    }
}
Vic
  • 189
  • 1
  • 15
  • Sorry for the late reply. The approach of creating `ColumnSeries` instead of `ColumnItems` is good, but the problem is I need to add the columns one by one. Adding a `ColumnSeries` will always add every item in its `ItemSource`, which is not the desired behaviour. – lucas.mdo Oct 21 '15 at 17:37
  • Let's say, for example, I want to plot 4 columns: by adding 4 `ColumnSeries` with the same `ItemSource`, I will end up with 4 columns, each of them composed by 4 others columns. Not good. – lucas.mdo Oct 21 '15 at 17:54
  • I don't know if I understand what you mean... You just need a Plot with 4 columns? In the example: 1 column for "Apples", 1 for "Pears", 1 for "Bananas" and 1 for (for example) "Strawberrys"? If this is not what you meant, maybe you could buid your desired plot with other tool and update a picture to the question? So we can better understand... – Vic Oct 22 '15 at 13:16
  • Not exactly 4, it was just an example (currently, I set the max number of columns to 8, and it's up to the user to choose how many he wants to plot at any given time). But you are correct when you say there must be just one column for each "category", like one for "Apples", one for "Pears", and so on. As I didn't find any suitable solution, I used the maneuver to rebuild the chart every time I add or remove an item. Not optimal, I must say, but it suited me well enough. – lucas.mdo Oct 22 '15 at 13:40
  • For this, you just need one ColumnSeries and Add / Remove Items from your `Items`... See my updated answer. – Vic Oct 23 '15 at 06:06
  • That worked. I don't know what my problem was, the Labels weren't been removed with the Item. Thanks for that! – lucas.mdo Oct 23 '15 at 13:04