Laden...

C# Winforms Balkendiagramm aus .csv Daten einlesen. Problem nur ein Barchart sichtbar

Letzter Beitrag vor 8 Tagen 8 Posts 233 Views
C# Winforms Balkendiagramm aus .csv Daten einlesen. Problem nur ein Barchart sichtbar

Hallo, ich komme mit meinem Problem nicht weiter deshalb frage ich hier nach. Ich habe ein C# Winforms Programm geschrieben um Aktienkennzahlen auszuwerten. Die Daten werden als .csv eingelesen und in der GUI kann ich dann die Aktie und die Kennzahl auswählen. Anschließend sollte es mir ein Balkendiagramm anzeigen. Das Problem ist wenn ich als X-Achse das Datum verwende (datumNeu[i]) wird mir nur ein Balken angezeigt. Sobald ich die zählende Variable i verwende zeigt es mir die Daten korrekt an.

Hier ist im Code die Stelle:

            for (int i = 0; i < anzahl; i++)
            {
                chart1.Series["Daten"].Points.AddXY(datumNeu[i], data[i]); // so funktioniert es: chart1.Series["Daten"].Points.AddXY(i, data[i]);
            }

Ich habe auch ein Foto hochgeladen. Foto1 es wird nur ein Balken angezeigt. Foto2 die Daten werden korrekt angezeigt, allerdings mit der X Achse als Zählvariable i. Hat jemand einen Tipp was ich da Falsch mache bzw. weshalb es mir nur einen Balken anzeigt sobald ich den String datumNeu[i]verwende?Danke.

Hier ist mein Code, ich habe diesen etwas gekürzt da wo die drei Punkt sind(z.B.Deklaration von Variablen):

using System;
using System.Drawing.Text;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace DateiLesen
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        int anzahl = 0;
        double[] data = new double[100];
        string[] datumNeu = new string[100];
        string auswahlKennzahlUeberschrift;
        //DateTime[] datumNeu = new DateTime[100];
        private void CmdLesen_Click(object sender, EventArgs e)
        {

            LblAnzeigen1.Text = $"Ausgewählte Aktie: " + $"{LstAktie.SelectedItem}\n";

            try
            {
                FileStream fs = new("test.csv", FileMode.Open);
                StreamReader sr = new(fs);
                LblAnzeige.Text = "";
                int i = 0;


                while (sr.Peek() != -1)
                {

                    string? zeile = sr.ReadLine();
                    if (zeile is not null)
                    {
                        string[] teil = zeile.Split(";");
                        //DateTime datum = Convert.ToDateTime(teil[0]);

                        .
                        .
                        .
                        double test = 0.0f;

                        if (aktie == $"{LstAktie.SelectedItem}")
                        {
                            datumNeu[i] = datum;

                            switch (LstKennzahl.SelectedIndex)
                            {

                                .
                                .
                                .

                            }

                            data[i] = test;
                           // LblAnzeige.Text += $"Datum:{datumNeu[i]} {data[i]} {i}\n"; Werte in einem LblAnzeige anzeigen
                            i++;

                            if (aktie == $"{LstAktie.SelectedItem}")
                            {
                                anzahl++;
                            }
                            LblAnzahl.Text = $" Anzahl Zeilen: {anzahl}\n";

                        }

                    }


                }
                sr.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }



        }

        private void Form1_Load(object sender, EventArgs e)
        {
           .
           .
           .
       

        }


        private void CmdZeichnen_Click(object sender, EventArgs e)
        {
            CmdLesen_Click(sender, e);

            chart1.Series["Daten"].Points.Clear();


            //Clear chart old series
            foreach (var series in chart1.Series)
            {
                series.Points.Clear();
            }

            chart1.Titles.Clear();  //Clear chart old title
            Title title = chart1.Titles.Add(auswahlKennzahlUeberschrift);
            title.Font = new System.Drawing.Font("Arial", 16, FontStyle.Bold);

            chart1.ChartAreas["ChartArea1"].AxisX.Interval = 1;
            chart1.ChartAreas["ChartArea1"].AxisX.Title = "Datum";
            chart1.ChartAreas["ChartArea1"].AxisY.Title = auswahlKennzahlUeberschrift;


            for (int i = 0; i < anzahl; i++)
            {
                chart1.Series["Daten"].Points.AddXY(datumNeu[i], data[i]); // so funktioniert es: chart1.Series["Daten"].Points.AddXY(i, data[i]);
            }

            anzahl = 0;

        }


    }
}

Nächstes mal solltest du den Debugger verwenden. Dann hättest du direkt gesehen, dass in deinem datumNeu Array immer der gleiche Wert steht, weil du in deinem Code das Auslesen/Verarbeiten des Datums auskommentiert hast:

//DateTime datum = Convert.ToDateTime(teil[0]);

siehe auch https://mycsharp.de/forum/threads/109261/artikel-debugger-wie-verwende-ich-den-von-visual-studio?page=1

Danke für die Antwort. Das hatte ich mal auskommentiert da ich aktuell das Datum als string darstelle: string datum = Convert.ToString(teil[0]);

Da hatte ich wohl zu viel vom Code abgeschnitten, es sieht da so aus:

...
string? zeile = sr.ReadLine();
if (zeile is not null)
{
    string[] teil = zeile.Split(";");
    //DateTime datum = Convert.ToDateTime(teil[0]);
    string datum = Convert.ToString(teil[0]);
    string aktie = teil[1];
    ...

Ich hatte versucht das Datum als string darzustellen da ich mit DateTime dasselbe Problem hatte. Ich habe mir mal die Daten so in einem Label mir anzeigen lassen:

            for (int i = 0; i < anzahl; i++)
            {
                LblAnzeige.Text += $"Datum:{datumNeu[i]} {data[i]} {i}\n"; //Werte mit LblAnzeige anzeigen
                chart1.Series["Daten"].Points.AddXY(datumNeu[i], data[i]); // so funktioniert es: chart1.Series["Daten"].Points.AddXY(i, data[i]);
                chart1.Series["Daten"].IsValueShownAsLabel = true;
            }

Und da wird schon das Datum korrekt angezeigt, siehe Foto rot markiert. Aber im Bar Chart Diagramm wird immer der selbe Wert als Datum angezeigt.

Von mir aus gesehen sollte das ArraydatumNeu[i]schon das richtige Datum enthalten, da dies auch im Label LblAnzeige.Textso angezeigt wird. Aber irgendwo mache ich Fehler.

Probier mal

chart1.Series["Daten"].XValueType = ChartValueType.String;

zu setzen.

Ok, habe ich versucht aber leider ohne Erfolg. Das Problem besteht weiterhin.

Das Problem ist, dass der Datapoint für die X/Y-Werte nur double verarbeiten kann. Also kannst Du keine Strings als X-Werte verwenden. Das wird dann alles zu 0 konvertiert und liegt demzufolge übereinander.

Du musst die X-Werte der Eigenschaft AxisLabel eines Datapoint zuweisen und die X-Werte hochzählen.

chart1.Series["Daten"].Points.Add(new DataPoint() { AxisLabel = datumNeu[i], XValue = i, YValues = [data[i]] });

Damit sollte das gewünschte Ergebnis angezeigt werden.

Ich habe da mal etwas vorbereitet und das funktioniert wunderbar

public partial class Form1 : Form
{
    private readonly Random random = new Random();

    public Form1()
    {
        InitializeComponent();
    }

    private Data GetRandomData()
    {
        return new Data
        {
            Name = "Daten",
            Title = "Kurs",
            Label = "Kurs",
            DataPoints = Enumerable
                .Range( 1, 31 )
                .Select( x => new DataPoint { Date = new DateTime( 2025, 1, x ), Value = random.Next( 250 ) } )
                .ToList()
                .AsReadOnly(),

        };
    }

    private void button1_Click( object sender, EventArgs e )
    {
        var data = GetRandomData();
        chart1.SetData( data );
    }
}

public static class ChartExtensions
{
    public static Chart SetData( this Chart chart, Data data )
    {
        chart.Series.Clear();
        chart.Series.AddData( data );
        chart.ChartAreas.Clear();
        chart.ChartAreas.AddData( data );
        chart.Titles.Clear();
        var title = chart.Titles.Add( data.Title );
        title.Font = new System.Drawing.Font( "Arial", 16, FontStyle.Bold );
        return chart;
    }

    public static Series AddData( this SeriesCollection collection, Data data )
    {
        Series series = new Series();
        series.Name = data.Name;
        series.ChartType = SeriesChartType.Column;
        series.XValueType = ChartValueType.DateTime;
        series.YValueType = ChartValueType.Auto;
        data.DataPoints.ToList().ForEach( x => series.Points.AddXY( x.Date, x.Value ) );
        collection.Add( series );
        return series;
    }

    public static ChartArea AddData( this ChartAreaCollection collection, Data data )
    {
        var area = new ChartArea();
        area.AxisX.Title = "Datum";
        area.AxisY.Title = data.Label;
        collection.Add( area );
        return area;
    }
}

public class Data
{
    public string Title { get; set; }
    public string Name { get; set; }
    public string Label { get; set; }
    public IReadOnlyCollection<DataPoint> DataPoints { get; set; }
}

public class DataPoint
{
    public DateTime Date { get; set; }
    public decimal Value { get; set; }
}

Hat die Blume einen Knick, war der Schmetterling zu dick.

@ Caveman : Vielen Dank, so klappt es.

@BlonderHans : Danke für das Beispiel. Ich werde es mir in der Ruhe mal ansehen.