3 votes

Tracer plusieurs axes Y par rapport à un axe X de DateTime dans LiveCharts

Dans mon application, j'ai quatre séries que je veux tracer sur un graphique linéaire. Chaque série est de la même taille, dont trois sont double et le dernier est un DateTime liste. Les trois séries doubles se présentent sous la forme d'une liste d'objets de classe de type GraphData qui ressemblent à ceci :

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

En outre, je souhaite disposer d'un axe Y propre à chacun d'entre eux.

Voici l'ensemble de mon programme jusqu'à présent, et il trace les trois graphiques sur ses propres axes sans problème.

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

Mi XAML semble simple :

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

GetGraphData() y GetTimeStamps() sont des fonctions factices ici qui simulent mes fonctions originales.

Maintenant cela fonctionne bien, sauf que l'axe des X n'est pas DateTime puisqu'il est évident que je ne l'ai pas tracé ainsi. Mais comment dois-je m'y prendre ?

La documentation officielle ainsi que ce poste SO montre seulement comment faire cela avec un seul Y-Axis .

2voto

Funk Points 4654

Je commencerais par apporter quelques modifications au modèle pour qu'il présente l'image complète. L'horodatage fait partie du point de données et vous devrez les regrouper pour que les graphiques en direct puissent être utilisés. mapper pour tracer les données.

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

Si vous voulez conserver le flux d'extraction actuel (CSV), vous pouvez simplement LINQ Zip les données sous une forme traçable.

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>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X