Stacked Chart - X-Achse als DateTime

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 5 Antworten in diesem Thema. Der letzte Beitrag () ist von Grimsey.

    Stacked Chart - X-Achse als DateTime

    Hallo zusammen,

    ich möchte für unsere Maschinen im Werk gerne eine Art Zustandsanzeige erstelle, ähnlich wie auf dem Bild im Anhang (Zustandsanzeige).
    Von den Maschinen werden zur Zeit diverse Parameter erfasst und in einer MSSQL-Datenbank gespeichert und auf einer firmeninternen Website dargestellt.
    Anhand des Parameters "Geschwindigkeit" ermittle ich mir bereits, ob eine Maschine stillsteht oder produziert. Die so ermittelten Zeitspannen stelle ich in einem Diagramm dar (Zustandsanzeige-IST).

    C#-Quellcode

    1. protected void Button1_Click(object sender, EventArgs e)
    2. {
    3. List<DateTime> lstStillstand = new List<DateTime>();
    4. List<DateTime> lstProduktion = new List<DateTime>();
    5. int i = 0;
    6. DateTime dtStart;
    7. TimeSpan dauerStillstand = TimeSpan.Zero;
    8. TimeSpan dauerProduktion = TimeSpan.Zero;
    9. ChartTest.Series.Clear();
    10. foreach (DataRow dr in ds2.Tables[0].Rows)
    11. {
    12. string str = dr.ItemArray[1].ToString(); // Zeitstempel
    13. dtStart = DateTime.Parse(str);
    14. double Geschwindigkeit = Convert.ToDouble(dr.ItemArray[5]); // Geschwindigkeit
    15. if (Geschwindigkeit <= 0)
    16. {
    17. lstStillstand.Add(dtStart);
    18. for (int j = 0; j < lstStillstand.Count; j++)
    19. {
    20. if (j == 0)
    21. {
    22. dauerStillstand = TimeSpan.Zero;
    23. }
    24. else
    25. {
    26. dauerStillstand = lstStillstand[j] - lstStillstand[j - 1];
    27. }
    28. i++;
    29. }
    30. ChartTest.Series.Add("Stopp" + i.ToString());
    31. ChartTest.Series["Stopp" + i.ToString()].ChartType = SeriesChartType.StackedBar;
    32. ChartTest.Series["Stopp" + i.ToString()].XValueType = ChartValueType.DateTime;
    33. ChartTest.Series["Stopp" + i.ToString()].Points.AddXY("Konti 2", dauerStillstand.TotalMinutes.ToString());
    34. ChartTest.Series["Stopp" + i.ToString()].Color = Color.Red;
    35. }
    36. else
    37. {
    38. lstProduktion.Add(dtStart);
    39. for (int j = 0; j < lstProduktion.Count; j++)
    40. {
    41. if (j == 0)
    42. {
    43. dauerProduktion = TimeSpan.Zero;
    44. }
    45. else
    46. {
    47. dauerProduktion = lstProduktion[j] - lstProduktion[j - 1];
    48. }
    49. i++;
    50. }
    51. ChartTest.Series.Add("Läuft" + i.ToString());
    52. ChartTest.Series["Läuft" + i.ToString()].ChartType = SeriesChartType.StackedBar;
    53. ChartTest.Series["Läuft" + i.ToString()].XValueType = ChartValueType.DateTime;
    54. ChartTest.Series["Läuft" + i.ToString()].Points.AddXY("Konti 2", dauerProduktion.TotalMinutes.ToString());
    55. ChartTest.Series["Läuft" + i.ToString()].Color = Color.Lime;
    56. }
    57. }
    58. ChartTest.ChartAreas[0].AxisY.Interval = 10;
    59. ChartTest.ChartAreas[0].AxisY.IntervalType = DateTimeIntervalType.Minutes;
    60. ChartTest.ChartAreas[0].AxisY.LabelStyle.Format = "HH:mm:ss";
    61. ChartTest.ChartAreas[0].AxisY.IntervalAutoMode = IntervalAutoMode.FixedCount;
    62. }


    Ich würde nun gerne noch die Beschriftung der X-Achse dahingehend anpassen, dass z.B. Datum und Uhrzeit für den angezeigten Bereich dargestellt werden, so dass man eine Zuordnung des Zeitraumes von Produktion und Stillstand treffen kann.
    Mir fällt nur kein gängiger Weg ein, wie ich das bewerkstelligen könnte.

    Könnt Ihr mir eventuell einen Denkanstoß liefern, wo ich nachlesen könnte um das gewünschte Verhalten zu realisieren?

    Habt recht vielen Dank im Voraus!
    Bilder
    • Zustandsanzeige.png

      12,92 kB, 675×85, 326 mal angesehen
    • Zustandsanzeige IST.png

      5,17 kB, 1.230×143, 320 mal angesehen
    @Grimsey Formatiere die Achse entsprechend. Form mit Chart und Combobox:
    Weise ComboBox1 folgende Items zu:

    Quellcode

    1. MMM
    2. MMMM
    3. dd.MM.yyyy
    4. MM.yyyy
    5. MMM.yyyy
    6. MMMM.yyyy
    7. MM.yy
    8. HH.mm.ss
    und dann

    VB.NET-Quellcode

    1. Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
    2. Chart1.ChartAreas(0).AxisX.LabelStyle.Format = ComboBox1.SelectedItem.ToString()
    3. Chart1.ChartAreas(0).AxisX.LabelStyle.Angle = 45 ' geneigte Anzeige
    4. End Sub

    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hallo zusammen,

    also ich scheine hier ein anderes, grundsätzliches, Problem zu haben.
    Bei einem "Stacked Bar Chart" sind ganz offensichtlich X- und Y-Achse vertauscht.
    Mit der Anpassung von @RodFromGermany wird lediglich die Beschriftung der linken senkrechten Achse angepasst.

    Wenn ich diese abwandle und für die Y-Achse übernehme, habe ich eine Achsenbeschriftung. Jedoch nicht in dem von mir gewünschten Format.
    Es stehen Werte wie 1E+17 drin....das sind ja offensichtlich die Zeitspannen, welche ich ermittelt habe. Macht ja auch Sinn....

    Ich hätte ja gerne eine Darstellung, aus der ersichtlich ist zu welchem ZeitPUNKT (und für welche Dauer) die Maschine produziert hat oder nicht.
    Dazu müsste ich irgendwie noch die Zeitpunkte auslesen und daraus eine Datenreihe für das Chart erstellen, oder?

    Grimsey schrieb:

    vertauscht ... die Beschriftung der linken senkrechten Achse
    Bei mir isses richtig.
    Probierma .AxisY..
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hallo @RodFromGermany,

    das habe ich ja bereits getan.

    Ich habe nun noch den Datentyp für die Y-Achse auf "Time" geändert und übergebe der Serie nun nicht mehr die Zeitspanne, sondern die jeweiligen Zeitpunkte als "DateTime".

    C#-Quellcode

    1. protected void Button1_Click(object sender, EventArgs e)
    2. {
    3. int i = 0;
    4. DateTime dtStart;
    5. TimeSpan dauerStillstand = TimeSpan.Zero;
    6. TimeSpan dauerProduktion = TimeSpan.Zero;
    7. ChartTest.Series.Clear();
    8. foreach (DataRow dr in ds2.Tables[0].Rows)
    9. {
    10. string str = dr.ItemArray[1].ToString(); // Zeitstempel
    11. dtStart = DateTime.Parse(str);
    12. double Geschwindigkeit = Convert.ToDouble(dr.ItemArray[5]); // Geschwindigkeit
    13. if (Geschwindigkeit <= 0)
    14. {
    15. i++;
    16. ChartTest.Series.Add("Stopp" + i.ToString());
    17. ChartTest.Series["Stopp" + i.ToString()].ChartType = SeriesChartType.StackedBar;
    18. ChartTest.Series["Stopp" + i.ToString()].YValueType = ChartValueType.Time;
    19. ChartTest.Series["Stopp" + i.ToString()].Points.AddXY("Konti2", dtStart);
    20. ChartTest.Series["Stopp" + i.ToString()].Color = Color.Red;
    21. }
    22. else
    23. {
    24. i++;
    25. ChartTest.Series.Add("Läuft" + i.ToString());
    26. ChartTest.Series["Läuft" + i.ToString()].ChartType = SeriesChartType.StackedBar;
    27. ChartTest.Series["Läuft" + i.ToString()].YValueType = ChartValueType.Time;
    28. ChartTest.Series["Läuft" + i.ToString()].Points.AddXY("Konti2", dtStart);
    29. ChartTest.Series["Läuft" + i.ToString()].Color = Color.Lime;
    30. }
    31. }
    32. ChartTest.ChartAreas[0].AxisY.LabelStyle.Format = "HH.mm.ss";
    33. ChartTest.ChartAreas[0].AxisY.LabelStyle.Angle = 45;
    34. }


    Das Result ist im Bild im Anhang zu sehen.
    Es wird jetzt immer "00.00.00" als Achsenbeschriftung ausgegeben.


    #### Update ####
    die Anzeige stimmt auch wieder...die Y-Werte die ich übergebe werden als Double interpretiert und sind alle sehr klein (z.B. 0,4685658)...das erklärt die Anzeige.
    Übergeben tue ich die Variable "dtStart", welche als DateTime deklariert ist und die auch den Korrekten Zeitstempel enthält, wenn ich das debugge.

    So richtig habe ich es noch nicht verstanden...
    Bilder
    • Zustandsanzeige IST2.png

      10,83 kB, 1.301×405, 315 mal angesehen

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Grimsey“ ()

    Ich habe einen Weg gefunden, die Daten in dem gewünschten Format darzustellen.

    C#-Quellcode

    1. protected void Button1_Click(object sender, EventArgs e)
    2. {
    3. List<DateTime> lstStillstand = new List<DateTime>();
    4. List<DateTime> lstProduktion = new List<DateTime>();
    5. int i = 0;
    6. double Geschwindigkeit;
    7. double dblZeit;
    8. string SerienName;
    9. string SerieAnfang;
    10. DateTime dtStart;
    11. DateTime dtAnfang;
    12. DateTime minDate;
    13. TimeSpan dauerStillstand = TimeSpan.Zero;
    14. TimeSpan dauerProduktion = TimeSpan.Zero;
    15. dtAnfang = DateTime.Parse(ds2.Tables[0].Rows[0].ItemArray[1].ToString());
    16. SerieAnfang = dtAnfang.ToString();
    17. ChartTest.Series.Clear();
    18. ChartTest.Series.Add("NullPunkt");
    19. ChartTest.Series["NullPunkt"].ChartType = SeriesChartType.StackedBar;
    20. ChartTest.Series["NullPunkt"].Points.AddXY("Konti2", dtAnfang);
    21. minDate = dtAnfang;
    22. foreach (DataRow dr in ds2.Tables[0].Rows)
    23. {
    24. SerienName = dr.ItemArray[1].ToString(); // Zeitstempel
    25. dtStart = DateTime.Parse(SerienName);
    26. Geschwindigkeit = Convert.ToDouble(dr.ItemArray[5]); // Geschwindigkeit
    27. dblZeit = Convert.ToDouble(dtStart.ToOADate());
    28. if (Geschwindigkeit <= 0)
    29. {
    30. lstStillstand.Add(dtStart);
    31. for (int j = 0; j < lstStillstand.Count; j++)
    32. {
    33. if (j == 0)
    34. {
    35. dauerStillstand = TimeSpan.Zero;
    36. }
    37. else
    38. {
    39. dauerStillstand = lstStillstand[j] - lstStillstand[j - 1];
    40. }
    41. i++;
    42. }
    43. ChartTest.Series.Add(SerienName);
    44. ChartTest.Series[SerienName].ChartType = SeriesChartType.StackedBar;
    45. ChartTest.Series[SerienName].Points.AddXY("Konti2", dauerStillstand.TotalDays);
    46. ChartTest.Series[SerienName].Color = Color.Red;
    47. }
    48. else
    49. {
    50. lstProduktion.Add(dtStart);
    51. for (int j = 0; j < lstProduktion.Count; j++)
    52. {
    53. if (j == 0)
    54. {
    55. dauerProduktion = TimeSpan.Zero;
    56. }
    57. else
    58. {
    59. dauerProduktion = lstProduktion[j] - lstProduktion[j - 1];
    60. }
    61. i++;
    62. }
    63. ChartTest.Series.Add(SerienName);
    64. ChartTest.Series[SerienName].ChartType = SeriesChartType.StackedBar;
    65. ChartTest.Series[SerienName].Points.AddXY("Konti2", dauerProduktion.TotalDays);
    66. ChartTest.Series[SerienName].Color = Color.Lime;
    67. }
    68. }
    69. ChartTest.ChartAreas[0].AxisY.LabelStyle.Format = "HH:mm";
    70. ChartTest.ChartAreas[0].AxisY.LabelStyle.Angle = 45;
    71. ChartTest.ChartAreas[0].AxisY.Minimum = minDate.ToOADate();
    72. }


    Der Knackpunkt war, dass ich erst eine Serie "NullPunkt" hinzugefügt habe, die nur einen Punkt besitzt und zwar den 1. Eintrag in der Tabelle.
    Weiterhin ist wichtig, dass man "AxisY.Minimum" ebenfalls auf diesen Wert einstellt.
    Als zweites habe ich erkannt, dass in der so vorgenommenen Einstellung, weitere Punkte in den hinzukommenden Serie scheinbar als ganze Tage interpretiert werden. Also habe ich die Werte in ".TotalDays" umgerechnet.

    Damit habe ich das gewünschte Ergebnis erst einmal erreicht.

    Was noch zu tun wäre:
    die Ermittlung der Produktions- und Stillstandsdauer erfolgt jeweils über eine FOR-Schleife, was doch recht lange dauert. Eigentlich benötigt man nur immer die Punkte, bei denen ein Zustandswechsel (stopp => run; run => stopp) stattfindet.
    Dies möchte ich jetzt noch optimieren.
    Bilder
    • Zustandsanzeige IST Final.png

      15,03 kB, 1.168×390, 303 mal angesehen