OxyPlot Mono для Android (он же Xamarin.Android) Неуместное рисование. (Серия столбцов с накоплением)

Я использую библиотеку OxyPlot и пытаюсь показать столбчатую диаграмму с накоплением, но она отображается неправильно.

Вот макет того, какой должна быть диаграмма:

Ожидаемая линейчатая диаграмма с накоплением

Вот как я создаю PlotModel:

private void InitWidget ()
{

    _goalsPlotModel = new PlotModel ("Metas") {
        LegendPlacement = LegendPlacement.Outside,
        LegendPosition = LegendPosition.BottomCenter,
        LegendOrientation = LegendOrientation.Horizontal,
        LegendBorderThickness = 0
    };

    SelectedChannel = new ListOfValue ();
    SelectedProduct = new Product ();

    SelectedChannel.Code = string.Empty;
    SelectedProduct.ProductCode = string.Empty;

    LoadFilters ();
    Refresh ();
}

Вот как я добавляю серию:

private void FillGoalsPlotModel ()
{
    _goalsPlotModel.Series.Clear ();
    _goalsPlotModel.Axes.Clear ();

    var goals = new ColumnSeries {
        Title = "Goals",
        FillColor = OxyColors.Orange,
        IsStacked = true,
        StrokeColor = OxyColors.Black,
        StrokeThickness = 1
    };

    var sales = new ColumnSeries {
        Title = "Sales",
        FillColor = OxyColors.LightGreen,
        IsStacked = true,
        StrokeColor = OxyColors.White,
        StrokeThickness = 1
    };

    var surplus = new ColumnSeries {
        Title = "Surplus",
        FillColor = OxyColors.Cyan,
        IsStacked = true,
        StrokeColor = OxyColors.Black,
        StrokeThickness = 1
    };

    var categoryAxisForMonths = new CategoryAxis { 
        Position = AxisPosition.Bottom 
    };

    var valueAxis = new LinearAxis (AxisPosition.Left) { 
        MinimumPadding = 0, 
        MaximumPadding = 0.06, 
        AbsoluteMinimum = 0 
    };


    foreach (IGoal goal in _goals) {

        if (goal.GetSales () > goal.GetGoalValue ()) {
            sales.Items.Add (new ColumnItem { Value = goal.GetGoalValue () });
            surplus.Items.Add (new ColumnItem { Value = goal.GetSurplus () });
        } else {
            sales.Items.Add (new ColumnItem { Value = goal.GetSales () });
            goals.Items.Add (new ColumnItem { 
                Value = goal.GetGoalValue() - goal.GetSales ()  
            });
        }
    }

    foreach (var month in GetMonths()) {
        categoryAxisForMonths.Labels.Add (month);
    }


    _goalsPlotModel.Series.Add (sales);
    _goalsPlotModel.Series.Add (goals);
    _goalsPlotModel.Series.Add (surplus);

    _goalsPlotModel.Axes.Add (categoryAxisForMonths);
    _goalsPlotModel.Axes.Add (valueAxis);


    RaisePropertyChanged (() => GoalsPlotModel);
}

А вот как это визуализируется:

Неуместная серия столбцов

Если я установлю IsStacked на false, он просто нарисует вертикальную гистограмму, но нижняя часть каждого бара будет на y = 0, как и ожидалось, но если IsStacked установить на true, каждая нижняя часть бара будет иметь разные значения y.

Это ошибка в Oxyplot для Mono для Android Renderer? Или просто я что-то не так делаю? (если да, то что я делаю не так?)


person Alberto Estrella    schedule 30.10.2013    source источник
comment
Эй, Альберто, не могли бы вы опубликовать некоторые данные (может быть, фиктивные), которые я мог бы протестировать?   -  person Noctis    schedule 04.11.2013


Ответы (1)


Ну, у меня работает следующее. Я приложу несколько скриншотов после кода, но я думаю, что ваша проблема заключалась в том, как вы добавляли точки в стеки.

Вы добавляете 2 точки (или столбцы) в каждом случае, но вам нужно присвоить значения 3 (третье равно нулю). В противном случае результаты будут складываться, пока вы не получите 3, и ничего не будет казаться правильным.

Мой Xaml прямолинеен:

<oxy:Plot Model="{Binding MyPlotModel}" />

Затем я вызываю этот метод из своего конструктора, чтобы создать и установить модель:

private void SetPlot()
{
    var model = new PlotModel("Metas")
    {
        LegendPlacement = LegendPlacement.Outside,
        LegendPosition = LegendPosition.BottomCenter,
        LegendOrientation = LegendOrientation.Horizontal,
        LegendBorderThickness = 0
    };

    var goals = new ColumnSeries {
        Title = "Goals",
        FillColor = OxyColors.Orange,
        IsStacked = true,
        StrokeColor = OxyColors.Black,
        StrokeThickness = 1
    };

    var sales = new ColumnSeries {
        Title = "Sales",
        FillColor = OxyColors.LightGreen,
        IsStacked = true,
        StrokeColor = OxyColors.White,
        StrokeThickness = 1
    };

    var surplus = new ColumnSeries {
        Title = "Surplus",
        FillColor = OxyColors.Cyan,
        IsStacked = true,
        StrokeColor = OxyColors.Black,
        StrokeThickness = 1
    };

    var categoryAxisForMonths = new CategoryAxis { 
        Position = AxisPosition.Bottom 
    };

    var valueAxis = new LinearAxis (AxisPosition.Left) { 
        MinimumPadding = 0, 
        MaximumPadding = 0.06, 
        AbsoluteMinimum = 0 
    };

    // Creating random data for 12 months
    for (int i = 0; i < 12; i++)
    {
        //var goal = 10;   // if you want a set goal, use this
        var goal = RandomHelper.RandomInt(8, 11); // otherwise use this
        var actualsales = RandomHelper.RandomInt(5, 15);

        if (actualsales > goal)
        {
            sales.Items.Add  (new ColumnItem( goal               ));
            surplus.Items.Add(new ColumnItem( actualsales-goal   ));
            goals.Items.Add  (new ColumnItem( 0                  ));
        }
        else
        {
            sales.Items.Add  (new ColumnItem( actualsales        ));
            goals.Items.Add  (new ColumnItem( goal - actualsales ));
            surplus.Items.Add(new ColumnItem( 0                  ));
        }

        // Next will create jan - dec in the labels
        categoryAxisForMonths.Labels.Add(CultureInfo.CurrentUICulture.DateTimeFormat.MonthNames[i]);

    }

    model.Series.Add (sales);
    model.Series.Add (goals);
    model.Series.Add (surplus);

    model.Axes.Add (categoryAxisForMonths);
    model.Axes.Add (valueAxis);

    MyPlotModel = model;
}
public PlotModel MyPlotModel { get; set; }

RandomHelper — это простой класс для помощи в получении случайных чисел:

public static class RandomHelper
{
    private static readonly Random RandomSeed = new Random();

    public static int RandomInt(int min, int max)
    {
        return RandomSeed.Next(min, max);
    }
}

И вот результаты:

Фиксированная цель

Случайная цель

Забавные строки — результат границ пустых столбцов, но вы сможете понять это :)

person Noctis    schedule 04.11.2013