Berechungen Chart, code optimieren

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von Amelie.

    Berechungen Chart, code optimieren

    Moin moin

    Habe das mit dem Ausdruck nun hinbekommen. Ich Chart werden meine Daten nun auch richtig angezeigt. Siehe Bildanhang.
    Jetzt die Frage, wie kann ich den Code hier ggf noch verbessern.

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Sub CalculateAndDisplayChart(stationNr As Integer, chart As Chart, dsClima As DataSet)
    2. ' DataTable abrufen
    3. Dim dt As DataTable = dsClima.Tables("Messwerte")
    4. ' Gruppieren der Daten nach Datum und Berechnung der Durchschnittswerte
    5. Dim groupedData = From row In dt.AsEnumerable()
    6. Where row.Field(Of Integer)("Station") = stationNr
    7. Group row By Datum = row.Field(Of Date)("Datum") Into Group
    8. Select New With
    9. {
    10. .Date = Datum,
    11. .AvgTemp1 = Group.Average(Function(r) If(r.Field(Of Double?)("Temperatur1"), 0)),
    12. .AvgTemp2 = Group.Average(Function(r) If(r.Field(Of Double?)("Temperatur2"), 0)),
    13. .AvgTemp3 = Group.Average(Function(r) If(r.Field(Of Double?)("Temperatur3"), 0)),
    14. .AvgAir1 = Group.Average(Function(r) If(r.Field(Of Double?)("Humidity1"), 0)),
    15. .AvgAir2 = Group.Average(Function(r) If(r.Field(Of Double?)("Humidity2"), 0)),
    16. .AvgAir3 = Group.Average(Function(r) If(r.Field(Of Double?)("Humidity3"), 0))
    17. }
    18. ' Ø Temperatur Ø Luftfeuchte hinzufügen
    19. If chart.Series.FindByName("Ø Temperatur") Is Nothing Then
    20. Dim avgtempSeries As New Series("Ø Temperatur")
    21. avgtempSeries.ChartType = SeriesChartType.Point
    22. chart.Series.Add(avgtempSeries)
    23. End If
    24. If chart.Series.FindByName("Ø Luftfeuchte") Is Nothing Then
    25. Dim avgairSeries As New Series("Ø Luftfeuchte")
    26. avgairSeries.ChartType = SeriesChartType.Point
    27. chart.Series.Add(avgairSeries)
    28. End If
    29. ' Temperaturserie hinzufügen
    30. If chart.Series.FindByName("Temp. Morgens") Is Nothing Then
    31. Dim tempSeries As New Series("Temp. Morgens")
    32. tempSeries.ChartType = ChartStyle
    33. chart.Series.Add(tempSeries)
    34. End If
    35. If chart.Series.FindByName("Temp. Mittags") Is Nothing Then
    36. Dim tempSeries As New Series("Temp. Mittags")
    37. tempSeries.ChartType = ChartStyle
    38. chart.Series.Add(tempSeries)
    39. End If
    40. If chart.Series.FindByName("Temp. Abends") Is Nothing Then
    41. Dim tempSeries As New Series("Temp. Abends")
    42. tempSeries.ChartType = ChartStyle
    43. chart.Series.Add(tempSeries)
    44. End If
    45. ' Luftfeuchtigkeitsserie hinzufügen
    46. If chart.Series.FindByName("Luftfeuchte Morgens") Is Nothing Then
    47. Dim airSeries As New Series("Luftfeuchte Morgens")
    48. airSeries.ChartType = ChartStyle
    49. chart.Series.Add(airSeries)
    50. End If
    51. If chart.Series.FindByName("Luftfeuchte Mittags") Is Nothing Then
    52. Dim airSeries As New Series("Luftfeuchte Mittags")
    53. airSeries.ChartType = ChartStyle
    54. chart.Series.Add(airSeries)
    55. End If
    56. If chart.Series.FindByName("Luftfeuchte Abends") Is Nothing Then
    57. Dim airSeries As New Series("Luftfeuchte Abends")
    58. airSeries.ChartType = ChartStyle
    59. chart.Series.Add(airSeries)
    60. End If
    61. For Each dayData In groupedData
    62. ' Daten für jeden Tag hinzufügen
    63. chart.Series("Ø Temperatur").Points.AddXY(dayData.Date.ToString("dd"), (dayData.AvgTemp1 + dayData.AvgTemp2 + dayData.AvgTemp3) / 3)
    64. chart.Series("Temp. Morgens").Points.AddXY(dayData.Date.ToString("dd"), dayData.AvgTemp1)
    65. chart.Series("Temp. Mittags").Points.AddXY(dayData.Date.ToString("dd"), dayData.AvgTemp2)
    66. chart.Series("Temp. Abends").Points.AddXY(dayData.Date.ToString("dd"), dayData.AvgTemp3)
    67. chart.Series("Ø Luftfeuchte").Points.AddXY(dayData.Date.ToString("dd"), (dayData.AvgAir1 + dayData.AvgAir2 + dayData.AvgAir3) / 3)
    68. chart.Series("Luftfeuchte Morgens").Points.AddXY(dayData.Date.ToString("dd"), dayData.AvgAir1)
    69. chart.Series("Luftfeuchte Mittags").Points.AddXY(dayData.Date.ToString("dd"), dayData.AvgAir2)
    70. chart.Series("Luftfeuchte Abends").Points.AddXY(dayData.Date.ToString("dd"), dayData.AvgAir3)
    71. Next
    72. chart.ChartAreas(0).AxisY.Interval = YInterval
    73. chart.ChartAreas(0).AxisX.Interval = 1
    74. chart.Series("Temp. Morgens").Color = Color.Lime
    75. chart.Series("Temp. Mittags").Color = Color.Red
    76. chart.Series("Temp. Abends").Color = Color.Blue
    77. chart.Series("Luftfeuchte Morgens").Color = Color.SandyBrown
    78. chart.Series("Luftfeuchte Mittags").Color = Color.DodgerBlue
    79. chart.Series("Luftfeuchte Abends").Color = Color.Magenta
    80. chart.Series("Ø Temperatur").Color = Color.DarkOrange
    81. chart.Series("Ø Luftfeuchte").Color = Color.Crimson
    82. End Sub



    Ich dachte erst an so etwas aber da stehe ich gerade auf dem Schlauch bzgl der Bezeichnungen. Es soll ja schon bei "Temp. Morgens" "Temp. Mittags" usw bleiben.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. ' Series für einzelne Temperatursensoren hinzufügen, falls nicht vorhanden
    2. For i As Integer = 1 To 3
    3. If chart.Series.FindByName($"Temp. Sensor {i}") Is Nothing Then
    4. Dim tempSeries As New Series($"Temp. Sensor {i}")
    5. tempSeries.ChartType = ChartStyle
    6. chart.Series.Add(tempSeries)
    7. End If
    8. Next

    Bilder
    • preview1.jpg

      483,81 kB, 1.150×602, 75 mal angesehen
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    Code:
    Ich denke allgemein diese Funktion sollte einer BindingSource nur die DataSource aufbereiten und gut ist. Dann machst du nur Tabellengeschubse und der Rest passiert ganz automatisch.
    Vergleiche mal mit einem DGV, da erstellst du die DGV-Spalten und Werte doch auch nicht händisch, so wie du hier die Series und Punkte hinzufügst.

    Aber sagen wir mal du machst es halt so, wie es is, dann würde ich dennoch zu typisierten DataTables raten. Dann kannst du unter anderem den LINQ etwas schöner machen, da fällt z.B. das AsEnumerable und DataRow.Field Gedöns raus.



    Visuell (sicher Geschmackssache):
    Gehe ich richtig in der Annahme, das die x-Achse Zeit darstellt?
    Sollten morgens, mittags und abends Datenpunkte dann nicht zeitlich versetzt sein?

    Messdatentechnisch würde man eher den Durschnitt als Linie angeben und den Rest als Punkte.
    @Haudruferzappeltnoch

    Die X-Axe sind die einzelnen Tage des Monat.
    ​Messdatentechnisch würde man eher

    Das kann ich umschalten mit dem Button "DiagrammTyp"!

    ​Datenpunkte dann nicht zeitlich versetzt sein?

    Wie meinst du das?

    ​sollte einer BindingSource nur die DataSource aufbereiten

    Da kann ich dir grad nicht folgen... bin glaube ich zu lange damit zugange ;)
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:

    Amelie schrieb:

    Die X-Axe sind die einzelnen Tage des Monat ...
    [Zeitlich versetzte Datenpunkte] Wie meinst du das?
    Tage eines Monat sind ja wohl Zeit. Gut 4 ist der vierte April und 5 ist der fünfte April. Und was ist dazwischen? Dazwischen ist doch auch Zeit.
    Entsprechend muss morgens doch ein bisschen nach der 4 kommen, mittags bei ca. 4,5 und abends kurz vor 5.


    Amelie schrieb:

    Da kann ich dir grad nicht folgen
    Bei dem Zitatschnipsel, was du gewählt hast, könnte ich auch nicht folgen, da geb ich dir vollkommen recht. Aber ich hab dann ja auch noch dazu geschrieben, du sollst es mal mit einem DataGridView vergleichen.
    Hast du schonmal eine DataTable per BindingSource an ein DataGridView gebunden?
    Bei Charts kann man das auch.
    @Haudruferzappeltnoch

    Die Daten sind im XML gespeichert und werden per DGV eingegeben / angezeigt und sind an ein Bindingsoure gebunden. (siehe Bildanhang)
    Habe aber noch nie ein Chart an ein Bindigsource gebunden.

    ​4 kommen, mittags bei ca. 4,5 und abends kurz vor 5.

    Warum sollte das so sein? Die Messungen laufen sehr konstant um: 08:00 / 12:00 / 18:00 Uhr
    Bilder
    • dgv-1.jpg

      190,43 kB, 768×268, 154 mal angesehen
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    Weil 12 Uhr 6 Stunden vor 18 Uhr ist. Was ist für dich zwischen 4 und 5? Für mich ist da Zeit dazwischen.

    Je nachdem, wo ein Tag beginnt, sei mal dahin gestellt, aber wenn ich den Tag um 0:00Uhr beginnen lasse, dann ist 4,5 = 4. April 12:00 Uhr = Mittags; 4,75 = 4.April 18:00 Uhr = Abends.

    Amelie schrieb:

    Habe aber noch nie ein Chart an ein Bindigsource gebunden
    Dann probiers aus. Wie gesagt da sparst du dir das meiste aus deiner Methode oben. Wenn du sogar schon ein DGV hast mit BindingSource kannst die wahrscheinlich gleich dafür hernehmen.
    Aber die Datenstruktur mit Morgens, mittags, abends so aufzuteilen ist ne wilde Nummer. Mach nicht nur ein Datum, sondern erfasse die vollständige Zeit zum Datensatz.

    Stell dir vor du willst nachts auch nochmal messen, dann musst du in deiner Variante neue Spalten einfügen und Code umschreiben. Und in der normalen Version ist es einfach ein Datensatz mit ner anderen Uhrzeit.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    Moin moin

    Also ja ich verstehe deine Logik mit den Zeiten. :) In der Tat waren meine ersten DataSets so aufgebaut, das für jede Messung noch ein TimeStamp gesetzt wurde.
    Das habe ich aber dann verworfen, weil der User meinte, er drucke ein leeres Sheet aus, trage da erstmal die Daten ein und später dann ins Programm.
    Das hat mich dann zu dieser Variante des DS geführt.

    Wie ich schrieb, werden hier nur 3 Messungen am Tag gemacht. Ob diese nun +- auf eine Std. genau sind ist nicht so wichtig.

    Im Anhang zu sehen, mein DataSet und ein leeres "Sheet".

    Das Sheet wird automatisch so für jeden neuen Monat erstellt, um es dem User einfacher zu machen, die Daten einzugeben.


    Werde mal guggen ob ich das irgendwie hin bekomme, ein Chart an eine Bindingsource zu binden und die Werte so zu berechnen.
    Bilder
    • dataset.jpg

      58,75 kB, 243×306, 63 mal angesehen
    • sheet.jpg

      211,74 kB, 1.040×392, 65 mal angesehen
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    Eventuell musst du dann anders an die Datenerfassung herangehen.
    Wie auch immer der User die Daten erfassen möchte, dies sollte keinen Einfluss auf die Struktur der Daten haben!
    Jetzt stell dir vor Kunde A will so und Kunde B anders. Machst du dann zwei verschiedene Datenstrukturen?

    Du kannst auch Comboboxen an die BindingSources binden, du kannst über Textboxen einen Datenwert reinholen und und und.
    Du kannst die Erfassung gänzlich von jeder Darstellung der Daten lösen, zum Beispiel ein Extraformular, da kann man dann vor allem allen möglichen Firlefanz einbauen, der es dem User einfacher macht zu erfassen. Wie z.B. automatisierte Vorwahlen des Zeitpunkts.
    Ein DataGridView ist meiner Meinung nach erstmal zum Angucken. Manche Datensätze lassen sich deutlich besser anpassen, wenn man sie in tabellarischer Form sieht, dann macht auch eine Bearbeitung der Daten per DGV Sinn.
    Hingegen einen vollständigen Datensatz in eine Tabelle einzuhacken, ist möglich, aber wie du siehst macht das Schwierigkeiten.

    Kennst du die vier Views von EDR? Der hat da eine einzige Datenstruktur und zeigt basically zig verschiedene Darstellungen dieser Daten. Gut möglich, dass da schon das Passende dabei ist.


    Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    Moin moin
    Habe meine Class für die Charts nun nochmal umgebaut. Die Verantwortlichkeiten mehr getrennt usw. :)

    Also ich finde es mit der Eingabe in einem DGV hierbei nun einfacher als über zusammengebaute Masken mit Textboxen etc.
    Das ganze sollte aber auch so einfach wie möglich gehalten werden. Quasi wie bei einer Eingabe in ExcelTabellen. Und die GUI sollte nicht überladen werden mit Controls. :)

    Ja die 4Views von EFR habe ich schon öfters angesehen... :)

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class ChartsCalculator
    2. Public Property MesswerteBindingSource As BindingSource
    3. Public YaxisInterval As Integer = 5 ' Wert für die Skalierung der Y-Axe der Charts
    4. Public Property ChartStyle As SeriesChartType ' Flag für Punkte/Linien Anzeige
    5. Public Property TempColor As Color ' Farbe der Temperaturanzeigen noch ohne funktion
    6. Public Property HuminiColor As Color ' Farben der Luftfeuchteanzeigen noch ohne funktion
    7. Public Sub New(messwerteBindingSource As BindingSource)
    8. Me.MesswerteBindingSource = messwerteBindingSource
    9. End Sub
    10. Public Sub CalculateChartValues(stationNr As Integer, chart As Chart)
    11. ' DataTable abrufen
    12. Dim datatable As DataTable = CType(MesswerteBindingSource.DataSource, DataSet).Tables("Messwerte")
    13. ' Gruppieren der Daten nach Datum und Berechnung der Durchschnittswerte
    14. Dim groupedData = From row In datatable.AsEnumerable()
    15. Where row.Field(Of Integer)("Station") = stationNr
    16. Group row By Datum = row.Field(Of Date)("Datum") Into Group
    17. Select New With
    18. {
    19. .Date = Datum,
    20. .AvgTemp1 = Group.Average(Function(r) If(r.Field(Of Double?)("Temperatur1"), 0)),
    21. .AvgTemp2 = Group.Average(Function(r) If(r.Field(Of Double?)("Temperatur2"), 0)),
    22. .AvgTemp3 = Group.Average(Function(r) If(r.Field(Of Double?)("Temperatur3"), 0)),
    23. .AvgAir1 = Group.Average(Function(r) If(r.Field(Of Double?)("Humidity1"), 0)),
    24. .AvgAir2 = Group.Average(Function(r) If(r.Field(Of Double?)("Humidity2"), 0)),
    25. .AvgAir3 = Group.Average(Function(r) If(r.Field(Of Double?)("Humidity3"), 0))
    26. }
    27. ' Ø Temperatur und Ø Luftfeuchte hinzufügen, falls nicht vorhanden
    28. AddAverageSeriesIfNotExists(chart)
    29. ' Temperatur- und Luftfeuchtigkeitsserien hinzufügen, falls nicht vorhanden
    30. AddTemperatureSeriesIfNotExists(chart)
    31. AddHumiditySeriesIfNotExists(chart)
    32. ' Daten für jeden Tag hinzufügen
    33. For Each dayData In groupedData
    34. Dim dayString As String = dayData.Date.ToString("dd")
    35. ' Ø Temperatur
    36. Dim avgTemperature As Double = (dayData.AvgTemp1 + dayData.AvgTemp2 + dayData.AvgTemp3) / 3
    37. chart.Series("Ø Temperatur").Points.AddXY(dayString, avgTemperature)
    38. ' Ø Luftfeuchte
    39. Dim avgHumidity As Double = (dayData.AvgAir1 + dayData.AvgAir2 + dayData.AvgAir3) / 3
    40. chart.Series("Ø Luftfeuchte").Points.AddXY(dayString, avgHumidity)
    41. ' Temperatur
    42. chart.Series("Temp. Morgens").Points.AddXY(dayString, dayData.AvgTemp1)
    43. chart.Series("Temp. Mittags").Points.AddXY(dayString, dayData.AvgTemp2)
    44. chart.Series("Temp. Abends").Points.AddXY(dayString, dayData.AvgTemp3)
    45. ' Luftfeuchte
    46. chart.Series("Luftfeuchte Morgens").Points.AddXY(dayString, dayData.AvgAir1)
    47. chart.Series("Luftfeuchte Mittags").Points.AddXY(dayString, dayData.AvgAir2)
    48. chart.Series("Luftfeuchte Abends").Points.AddXY(dayString, dayData.AvgAir3)
    49. Next
    50. ' Achsenintervalle setzen
    51. SetIntervals(chart)
    52. ' Farben setzen
    53. SetChartColors(chart)
    54. End Sub
    55. Private Sub SetIntervals(chart As Chart)
    56. ' Achsenintervalle setzen
    57. chart.ChartAreas(0).AxisY.Interval = YaxisInterval
    58. chart.ChartAreas(0).AxisX.Interval = 1
    59. End Sub
    60. Private Sub SetChartColors(chart As Chart)
    61. ' Farben für Temperaturserien setzen
    62. chart.Series("Temp. Morgens").Color = Color.Lime
    63. chart.Series("Temp. Mittags").Color = Color.Red
    64. chart.Series("Temp. Abends").Color = Color.Blue
    65. ' Farben für Luftfeuchtigkeitsserien setzen
    66. chart.Series("Luftfeuchte Morgens").Color = Color.SandyBrown
    67. chart.Series("Luftfeuchte Mittags").Color = Color.DodgerBlue
    68. chart.Series("Luftfeuchte Abends").Color = Color.Magenta
    69. ' Farben für Ø Temperatur und Ø Luftfeuchte setzen
    70. chart.Series("Ø Temperatur").Color = Color.DarkOrange
    71. chart.Series("Ø Luftfeuchte").Color = Color.Crimson
    72. End Sub
    73. Private Sub AddAverageSeriesIfNotExists(chart As Chart)
    74. If chart.Series.FindByName("Ø Temperatur") Is Nothing Then
    75. Dim avgtempSeries As New Series("Ø Temperatur")
    76. avgtempSeries.ChartType = SeriesChartType.Point
    77. chart.Series.Add(avgtempSeries)
    78. End If
    79. If chart.Series.FindByName("Ø Luftfeuchte") Is Nothing Then
    80. Dim avgairSeries As New Series("Ø Luftfeuchte")
    81. avgairSeries.ChartType = SeriesChartType.Point
    82. chart.Series.Add(avgairSeries)
    83. End If
    84. End Sub
    85. Private Sub AddTemperatureSeriesIfNotExists(chart As Chart)
    86. Dim temperatureSeriesNames As New List(Of String) From {"Temp. Morgens", "Temp. Mittags", "Temp. Abends"}
    87. ' Schleife durch die Namen der Temperaturserien
    88. For Each seriesName In temperatureSeriesNames
    89. ' Überprüfen, ob die Serie bereits im Chart vorhanden ist
    90. If chart.Series.FindByName(seriesName) Is Nothing Then
    91. ' Wenn nicht, Serie hinzufügen
    92. Dim tempSeries As New Series(seriesName)
    93. tempSeries.ChartType = ChartStyle
    94. chart.Series.Add(tempSeries)
    95. End If
    96. Next
    97. End Sub
    98. Private Sub AddHumiditySeriesIfNotExists(chart As Chart)
    99. Dim luftfeuchteSeriesNames As New List(Of String) From {"Luftfeuchte Morgens", "Luftfeuchte Mittags", "Luftfeuchte Abends"}
    100. ' Schleife durch die Namen der Luftfeuchteserien
    101. For Each seriesName In luftfeuchteSeriesNames
    102. ' Überprüfen, ob die Serie bereits im Chart vorhanden ist
    103. If chart.Series.FindByName(seriesName) Is Nothing Then
    104. ' Wenn nicht, Serie hinzufügen
    105. Dim airSeries As New Series(seriesName)
    106. airSeries.ChartType = ChartStyle
    107. chart.Series.Add(airSeries)
    108. End If
    109. Next
    110. End Sub
    111. End Class

    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh: