"Einfache" Statistik erfassen, Speichern & Anzeigen



  • Hallo Leute ...

    Ich möchte in meinem Programm mehrere Statistik Funktionen anbieten.

    Für den Überblick:

    Das Programm bietet eine Lernfunktion, also eine Art Quiz bei dem jede Menge Fachfragen abgefragt werden. Schwierigkeitsgrad & Fachbereiche sind natürlich frei wählbar.

    Zur Statistik:

    Folgende Funktionen halte ich für sinnvoll, da das ganze später ja auch einen ernsten Zweck erfüllen soll:

    - aktuelle Statistik ( beim laufenden Quiz - richtige / falsche Antworten)
    - Statistik nach Fachbereichen ( Worin bin ich stark, worin schlecht ?)
    - Langzeitstatistik (Übungstage und Tendenz)

    Punkt 1 & 3 habe ich bereits "mit meinen Möglichkeiten" versucht umzusetzen. Verwendet habe ich dazu zedGraph.

    Folgende Variablen verwende ich:

    richtigBeantwortet
    falschBeantwortet
    Fachbereich
    Datum
    Schwierigkeit

    welche dann irgendwann via dieser "gebasteleten" Funktion gespeichert wird:

    public bool saveStatistik(BenutzerInfoKlasse IBenutzerInfoKlasse, int richtig, int falsch, DateTime datum, int schwierigkeit)
            {            
                if (IBenutzerInfoKlasse.benutzername == null) return false;
    
                try
                {
                    StreamWriter sr = new StreamWriter(System.IO.Path.Combine(IBenutzerInfoKlasse.benutzerdatenpfad, IBenutzerInfoKlasse.benutzername + ".sta"), true);                
    
                    sr.WriteLine("<datum>" + datum.ToShortDateString () +"</datum>"+"<richtig>" + richtig.ToString () + "</richtig>" + "<falsch>" + falsch.ToString () + "</falsch>" + "<schwierigkeit>" + schwierigkeit.ToString () + "</schwierigkeit>");
    
                    sr.Close();
                    return true;
                }
    
                catch (Exception e)
                {
                    ShowErrorMessage(e);
                    return false;
                }
            }
    

    Und via:

    protected void TloadStatistiken(BenutzerInfoKlasse IBenutzerInfoKlasse)
            {
                DiskIO IDiskIO = new DiskIO();
    
                List<String[]> rohdaten = IDiskIO.loadStatistik(IBenutzerInfoKlasse);
                List<String> bewertungsdatum = new List<String>();
                List<statistikstruct> structlist = new List<statistikstruct>();
                List<statistikstruct> structlisttemp = new List<statistikstruct>();
    
                String[] buffer;
                int richtig, falsch;
    
                //prüfen ob Statistik Daten bestehen
                if (rohdaten == null || rohdaten.Count < 1)
                {
                    IQuizPanel.IHauptprogramm.status.Text = "Es wurden keine Statistikdaten gefunden.";
                    return;
                }
    
                foreach (String [] set in rohdaten)
                {
                    buffer = (String[])set;
                    String datum = buffer[0];
    
                    richtig = Convert.ToInt16(buffer[1]);
                    falsch = Convert.ToInt16(buffer[2]);
    
                    if (bewertungsdatum.Contains(datum))
                    {
                        //Datum bereits vorhanden
                       foreach (statistikstruct stat in structlist)
                       {
                           if (stat.datum == datum)
                           {
                               richtig = stat.richtig + richtig;
                               falsch = stat.falsch + falsch;
    
                               statistikstruct Istatistikstruct = new statistikstruct();
                               Istatistikstruct.datum = datum;
                               Istatistikstruct.richtig = richtig;
                               Istatistikstruct.falsch = falsch;
    
                               structlisttemp.Add(Istatistikstruct);
                               structlist.Remove(stat);
                               break;
                           }
                       }
                    }
    
                    else
                    {
                        //Datum noch nicht vorhanden
                        statistikstruct Istatistikstruct = new statistikstruct();
                        Istatistikstruct.datum = datum;
                        Istatistikstruct.richtig = richtig;
                        Istatistikstruct.falsch = falsch;
    
                        structlist.Add(Istatistikstruct);
    
                        bewertungsdatum.Add(datum);
                        continue;
                    }
    
                }
    
                //Daten sind in der Liste vollständig
                foreach (statistikstruct s in structlisttemp) structlist.Add (s);
    
                statistikdaten = structlist;
                zeitpunkte = bewertungsdatum;
    
            }
    

    ...so geladen:

    public List<String[]> loadStatistik(BenutzerInfoKlasse IBenutzerInfoKlasse)
            {
                List<String[]> daten = new List<string[]>();
    
                try
                {
                    StreamReader r = new StreamReader(System.IO.Path.Combine(IBenutzerInfoKlasse.benutzerdatenpfad, IBenutzerInfoKlasse.benutzername + ".sta"), true);
    
                    String[] trennzeichen = new String[] { "<datum>", "</datum>", "<richtig>", "</richtig>", "<falsch>", "</falsch>" };
    
                    String readbuffer; //für den Streamreader  
    
                    while (!r.EndOfStream)
                    {
                        readbuffer = "";
                        readbuffer = r.ReadLine();
    
                        //Trennt die TAGS von den Daten in ein String Array
                        daten.Add(readbuffer.Split(trennzeichen, StringSplitOptions.RemoveEmptyEntries));
                    }
                }
                catch (Exception)
                {
                    //MessageBox.Show("Fehler bei DiskIO - loadStatistik");
                    return null;
                }
    
                return daten;
            }
    

    Ich gebe zu, alles nicht das wahre. Wie würdet ihr das lösen ?



  • Also wenn du unbedingt mit dem StreamWriter und StreamReader arbeiten willst, dann pack die bitte in ein "using-Block".
    So wie das aussieht willst du ja XML Speichern. Dafür gibt es bereits Klassen in .NET die dich dabei ein wenig unterstützen.
    Schau dir dazu mal, XmlWriter, XDocument und Linq-To-Xml an.



  • Okay. Manchmal verstehe ich im nachhinein selber nicht mehr was ich mache. Bestimmt 80 % meines Progis verarbeiten auf irgendeine Weise XML mit den von dir angesprochenen Klassen.

    Habe alles mal umgenudelt, wobei die Daten nun wie folgt als XML Document gespeichert und geladen werden:

    <?xml version="1.0"?>
    <Statistik>
      <Datum>26.01.2011<richtig>0</richtig><falsch>8</falsch><Schwierigkeit>0</Schwierigkeit><Fachbereich>5</Fachbereich></Datum>
      <Datum>26.01.2011<richtig>3</richtig><falsch>1</falsch><Schwierigkeit>0</Schwierigkeit><Fachbereich>5</Fachbereich></Datum>
    </Statistik>
    

    Wobei ich nun wieder bei meiner Fragestellung wäre, wobei ich die "aktuelle Statistik" gerne erstmal bei Seite lassen würde, da diese nicht auf die XML Daten zugreift.

    Wie verarbeite ich nun die Daten ? Alles in ein Array oder direkt aus dem XMLDocument verarbeiten ? Und nutze ich wirklich zedGraph ? Ich möchte das ganze gerne ziemlich übersichtlich haben, vielleicht nen kleines UserControl / Form an der linken oberen Ecke des Desktops. zedGraph ist bei kleiner Skalierung schlecht lesbar, finde ich. Was würdet ihr nutzen ?



  • Guten Morgen

    Brauche nocheinmal eure Hilfe:

    Beim laden der Statistik Form wird dies aufgerufen:

    private void InitChartAktuell(ZedGraphControl zgc)
            {            
                myPane = zgc.GraphPane;
                myPane.CurveList.Clear();                      
    
                //Titel
                myPane.Title.Text = "Statistik  " + IQuizPanel.IHauptprogramm.IBenutzerInfo.benutzername;
                myPane.Title.FontSpec.Size = 20;
    
                //X Labels          
                myPane.XAxis.Title.FontSpec.Size = 15;
                myPane.YAxis.Title.Text = "Anzahl";
                myPane.YAxis.Title.FontSpec.Size = 15;
    
                try
                {
                    //XLabels
                    string[] XLabels = { "Übungstag: " + DateTime.Now.ToShortDateString () };                
    
                    myPane.XAxis.Type = AxisType.Text;
                    myPane.XAxis.Scale.TextLabels = XLabels;
                    myPane.XAxis.Scale.FontSpec.Size = 15;
    
                    //Y Labels
                    myPane.YAxis.Type = AxisType.Exponent;
                    myPane.YAxis.Scale.FontSpec.Size = 15;
                    myPane.YAxis.Scale.FontSpec.IsBold = true;
    
                    //Refresh
                    zgc.AxisChange();
    
                    zgc.ZoomOutAll(myPane);
                    zgc.Refresh();
                }
                catch (Exception)
                { }
            }
    

    Via Menü hat der User die Möglichkeit die anderen Statistiken anzeigen zu lassen:

    private void aktuelleStatistikToolStripMenuItem_Click(object sender, EventArgs e)
            {
                if (activChart == 0)
                {
                    UpdateChartAktuell(zedGraphControl1);
                    return;
                }
    
                LangzeitanzeigenToolStripMenuItem.Enabled = true;
                AktuellanzeigenToolStripMenuItem2.Enabled = false;
                FachbereichanzeigenToolStripMenuItem1.Enabled = true;
                SchwierigkeitToolStripMenuItem.Enabled = true;
    
                InitChartAktuell(zedGraphControl1);
    
                activChart = 0;
            }              
    
            private void langzeitstatistikAnzeigenToolStripMenuItem_Click(object sender, EventArgs e)
            {
                if (activChart == 1) return; //evtl. neu zeichnen ?
    
                myPane.CurveList.Clear();
    
                LangzeitanzeigenToolStripMenuItem.Enabled = false;
                AktuellanzeigenToolStripMenuItem2.Enabled = true;
                FachbereichanzeigenToolStripMenuItem1.Enabled = true;
                SchwierigkeitToolStripMenuItem.Enabled = true;
    
                InitChartLangzeit(zedGraphControl1);
    
                activChart = 1;
            }
    usw...
    

    Hier der Code zur Langzeitstatistik:

    public void InitChartLangzeit(ZedGraphControl zgc)
            {
                if (XMLStatistik == null) return;
                if (structlist == null) structlist = new List<statistikstruct>();
    
                zgc.Invalidate();
                zgc.GraphPane.GraphObjList.Clear();
    
                List<String> zeitpunkte = new List<string>();
    
                //Alle Daten (Datums) in eine Liste holen
                foreach (XmlNode dateNode in XMLStatistik.DocumentElement.ChildNodes) if (zeitpunkte.Contains (dateNode.FirstChild.InnerText) == false) zeitpunkte.Add (dateNode.FirstChild.InnerText);
    
                foreach (String zeitpunkt in zeitpunkte)
                {
                    statistikstruct s = new statistikstruct();
                    s.datum = zeitpunkt;
    
                    foreach (XmlNode node in XMLStatistik.DocumentElement.ChildNodes)
                    {
                        //Wenn Datum übereinstimmt - richtig und falsch zusammenzehlen
                        if (node.FirstChild.InnerText != zeitpunkt) continue;                    
                        else
                        {
                            s.richtig = s.richtig + Convert.ToInt16(node.ChildNodes[1].InnerText);
                            s.falsch = s.falsch + Convert.ToInt16(node.ChildNodes[2].InnerText);
                        }                    
                    }
    
                    structlist.Add(s);
                }
    
                myPane = zgc.GraphPane;
    
                //Needed for redrawing the chart, to remove old curves
                //myPane.CurveList.Clear();
    
                // Set the title and axis labels
                myPane.Title.Text = "Langzeitstatistik " + IQuizPanel.IHauptprogramm.IBenutzerInfo.benutzername;
                myPane.XAxis.Title.Text = "Datum der Bewertung";
                myPane.YAxis.Title.Text = "Falsch / Richtig";
                // Make up some data points
    
                string[] labels = zeitpunkte.ToArray();
                List<double> ri = new List<double>();
                List<double> fa = new List<double>();
    
                foreach (statistikstruct s in structlist)
                {
                    ri.Add(s.richtig);
                    fa.Add(s.falsch);
                }
    
                double[] y2 = ri.ToArray();
                double[] y = fa.ToArray();
    
                // Generate a red bar with "Curve 1" in the legend
                BarItem myCurve = myPane.AddBar("Falsch", null, y, Color.Red);
                // Fill the bar with a red-white-red color gradient for a 3d look
                myCurve.Bar.Fill = new Fill(Color.Red, Color.White, Color.Red);
    
                // Generate a blue bar with "Curve 2" in the legend
                myCurve = myPane.AddBar("Richtig", null, y2, Color.LimeGreen);
                // Fill the bar with a Blue-white-Blue color gradient for a 3d look
                myCurve.Bar.Fill = new Fill(Color.LimeGreen, Color.White, Color.LimeGreen);
    
                // Draw the X tics between the labels instead of at the labels
                myPane.XAxis.MajorTic.IsBetweenLabels = true;
    
                // Set the XAxis to Text type
                myPane.XAxis.Type = AxisType.Text;
    
                // Set the XAxis labels
                myPane.XAxis.Scale.TextLabels = labels;
                //myPane.XAxis.Scale.FontSpec.Size = 10;
    
                // Set the bar type to stack, which stacks the bars by automatically accumulating the values
                myPane.BarSettings.Type = BarType.Stack;
    
                // Calculate the Axis Scale Ranges
                zgc.AxisChange();
    
                zgc.ZoomOutAll(myPane);
                zgc.Refresh();
            }
    

    Das Problem ist nun, das bei einem Wechsel von einer Statistik zur anderen, die alte Statistik nicht gelöscht, sondern die neue angehängt wird. Wie umgehe ich das ?


Anmelden zum Antworten