Нарисуйте несколько осей Y против одной оси X DateTime в LiveCharts - PullRequest
2 голосов
/ 19 апреля 2019

В моем приложении у меня есть четыре серии, которые я хочу построить на линейном графике. Каждая серия имеет одинаковый размер, три из которых double, а последняя - список DateTime. Три двойных ряда входят в список объектов класса типа GraphData, которые выглядят так:

public class GraphData
{
    public string Name { get; set; }
    public List<double> Data { get; set; }
}

В качестве дополнительного требования я хочу иметь собственную ось Y для каждого из них.

Здесь представлена ​​вся моя программа, и она без проблем строит три графика на своих осях.

public partial class MainWindow : Window
{
    public SeriesCollection SeriesCollection { get; set; }
    public AxesCollection YAxesCollection { get; set; }
    public List<GraphData> GraphDatas { get; set; }
    public List<DateTime> TimeStamps { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        GraphDatas = GetGraphData();
        TimeStamps = GetTimeStamps(GraphDatas[0].Data.Count);
        Plot();
    }

    private void Plot()
    {
        SeriesCollection = new SeriesCollection();
        YAxesCollection = new AxesCollection();

        var count = 0;
        foreach (var data in GraphDatas)
        {
            var gLineSeries = new GLineSeries
            {
                Title = data.Name,
                Values = data.Data.AsGearedValues().WithQuality(Quality.Low),
                PointGeometry = null,
                Fill = Brushes.Transparent,
                ScalesYAt = count
            };

            SeriesCollection.Add(gLineSeries);
            YAxesCollection.Add(new Axis() { Title = data.Name });
            count++;
        }

        DataContext = this;
    }

    private List<GraphData> GetGraphData()
    {
        var dataList = new List<GraphData>
        {
            new GraphData() { Name = "DataA", Data = new List<double>() { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 11.0, 11.0, 9.9, 8.8, 7.7, 6.6, 5.5, 4.4, 3.3, 2.2, 1.1, } },
            new GraphData() { Name = "DataB", Data = new List<double>() { 26, 33, 65, 28, 34, 55, 25, 44, 50, 36, 26, 37, 43, 62, 35, 38, 45, 32, 28, 34 } },
            new GraphData() { Name = "DataC", Data = new List<double>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 } }
        };
        return dataList;
    }

    private List<DateTime> GetTimeStamps(int limit)
    {
        var timeStamps = new List<DateTime>();
        var now = DateTime.Now;
        for (int i = 0; i < limit; i++)
        {
            if (i == 0)
                timeStamps.Add(now);
            else
            {
                now = now.AddDays(1);
                timeStamps.Add(now);
            }
        }
        return timeStamps;
    }
}

Мой XAML выглядит просто:

<Grid>
    <lvc:CartesianChart Series="{Binding SeriesCollection}" 
                        AxisY="{Binding YAxesCollection}"
                        DisableAnimations="True"
                        LegendLocation="Right">
    </lvc:CartesianChart>
</Grid>

GetGraphData() и GetTimeStamps() - это фиктивные функции, которые имитируют мои оригинальные функции.

Теперь это работает нормально, за исключением того, что ось X не DateTime, так как, очевидно, я не построил это так. Но как мне это сделать?

Официальная документация , а также в этом SO Post показывает, как это сделать только с одним Y-Axis.

1 Ответ

1 голос
/ 22 апреля 2019

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

public class DataPoint
{
    public DataPoint(DateTime timeStamp, double value)
    {
        TimeStamp = timeStamp;
        Value = value;
    }

    public double Value { get; }
    public DateTime TimeStamp { get; }
}

public class GraphData
{
    public string Name { get; set; }
    public List<DataPoint> Data { get; set; }
}

Если вы хотите сохранить текущий поток извлечения (CSV), вы можете просто LINQ Zip данные в графическом виде.

public partial class MainWindow : Window
{
    public SeriesCollection SeriesCollection { get; set; }
    public Func<double, string> Formatter { get; set; }
    public AxesCollection YAxesCollection { get; set; }
    public List<GraphData> GraphDatas { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        var timeStamps = GetTimeStamps(20);
        GraphDatas = GetGraphData(timeStamps);
        Plot();
    }

    private List<GraphData> GetGraphData(List<DateTime> timeStamps)
    {
        var valuesA = new List<double>() { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 11.0, 11.0, 9.9, 8.8, 7.7, 6.6, 5.5, 4.4, 3.3, 2.2, 1.1, };
        var valuesB = new List<double>() { 26, 33, 65, 28, 34, 55, 25, 44, 50, 36, 26, 37, 43, 62, 35, 38, 45, 32, 28, 34 };
        var valuesC = new List<double>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };

        List<DataPoint> MergeData(List<double> values) => timeStamps.Zip(values, (x, y) => new DataPoint(x, y)).ToList();

        var dataList = new List<GraphData>
        {
            new GraphData() { Name = "DataA", Data = MergeData(valuesA) },
            new GraphData() { Name = "DataB", Data = MergeData(valuesB) },
            new GraphData() { Name = "DataC", Data = MergeData(valuesC) },
        };
        return dataList;
    }

    private void Plot()
    {
        var mapper = Mappers.Xy<DataPoint>()
           .X(dp => (double)dp.TimeStamp.Ticks)
           .Y(dp => dp.Value);

        SeriesCollection = new SeriesCollection(mapper);
        YAxesCollection = new AxesCollection();

        var count = 0;
        foreach (var data in GraphDatas)
        {
            var gLineSeries = new GLineSeries
            {
                Title = data.Name,
                Values = data.Data.AsGearedValues().WithQuality(Quality.Low),
                PointGeometry = null,
                Fill = Brushes.Transparent,
                ScalesYAt = count
            };

            SeriesCollection.Add(gLineSeries);
            YAxesCollection.Add(new Axis() { Title = data.Name });
            count++;
        }

        Formatter = value => new DateTime((long)value).ToString("yyyy-MM:dd HH:mm:ss");

        DataContext = this;
    }

    private List<DateTime> GetTimeStamps(int limit)
    {
        var timeStamps = new List<DateTime>();
        var now = DateTime.Now;
        for (int i = 0; i < limit; i++)
        {
            if (i == 0)
                timeStamps.Add(now);
            else
            {
                now = now.AddDays(1);
                timeStamps.Add(now);
            }
        }
        return timeStamps;
    }
}

XAML

<lvc:CartesianChart Series="{Binding SeriesCollection}" 
                    AxisY="{Binding YAxesCollection}"
                    DisableAnimations="True"
                    LegendLocation="Right">
    <lvc:CartesianChart.AxisX>
        <lvc:Axis LabelFormatter="{Binding Formatter}" />
    </lvc:CartesianChart.AxisX>
</lvc:CartesianChart>
...