SVG Diagramm erzeugen mit Python und C# im Vergleich

Gerade im IoT-Umfeld nehmen die Datenmengen gerne schwindelerregende Umfänge an. Die einzige Chance, den Überblick zu behalten, ist eine geeignete Datenvisualisierung. Der erste Schritt bei Zeitreihendaten ist die Erstellung einer Infografik in Form eines xy-Liniendiagramms. Dazu sind grundsätzlich keine Grafiktools notwendig, eine einfaches in Python oder C# geschriebenes Programm genügt. Um abschätzen zu können, welche Programmierumgebung angenehmer ist, sind hier der Python- und der C#-Quellcode für das gleiche Ergebnis dargestellt.

09.01.2024

Das Anwendungsszenario

Das Beispiel verwendet Daten, die von einer WLAN-Steckdose gesammelt und im Internet gespeichert werden. Daten für bis zu drei Tagen sind über einen Webservice im CSV-Format ladbar. Die Daten enthalten einen Unix-Zeitstempel, einen menschenlesbaren Zeitstring, die jeweils aktuelle durch die WLAN-Steckdose gemessene Leistung in Watt und die über die Zeit kumulierte  (integrierte) Leitung sprich Energie in Kilo-Wattstunden.

Aus den Daten wird eine x-y-Liniengrafik erzeugt und auf der eigenen Festplatte abgespeichert. Das Programm wurde zunächst mit Python entwickelt und dann – möglichst eins zu eins – in Dot Net C# umgesetzt. Das führt zu einem wenig schönen C#-Code, lässt aber den Vergleich zwischen Python und C# als Programmiersprachen zu.

Persönliche Wertung (Achtung subjektiv): Nach einigen Experimenten mit solchen ETL-Prozessen bin ich für mich zum Schluss gekommen, dass ich mit Python schneller zu einem brauchbaren Ergebnis gelange. Dabei bin ich weder Python- noch C# / Dot Net Fan.

Die erzeugte Grafik

Screenshot einer SVG-Infografik im Browser Chrome

Abb. 1: Die von den Programmen erzeugte SVG-Grafik, hier als Screenshot im Browse Chrome. Dargestellt sind in der x-Achse die Zeit beginnend mit vorgestern Null Uhr bis jetzt, in schwarz die von der WLAN-Steckdose gemessene Leistung, in rot die kumulierte Leistung sprich Energie. Sowohl Leistung als auch Energie sind in der y-Achse so skaliert, dass sie die Zeichenfläche ausfüllen.

Vorgehen und Programmierung

Python mit Thonny

Für die Programmierung des Python-Programms diente die einfache IDE Thonny. Thonny bringt schon die aktuelle Python-Version mit und ist mit einem Mausklick zu installieren.

C# mit Visual Studio Code

Für die Programmierung in C# wurde Dot Net in der aktuellen Version (heißt: ist in einem Jahr hoffnungslos veraltet) und Visual Studio Code verwendet. Zunächst wurde im Terminal ein Hello-World-Programm erzeugt mit „dotnet new console“, dann der Python Quelltext im Edotor einfügt und manuell in C# übersetzt. Da Python nicht typisiert ist, führt das zu einigen umständlichen Konstrukten. Um die Vergleichbarkeit zu erhalten, wurden auch in C# Listen und keine starren Arrays verwendet.

In der aktuellen Visual Studio Code Version genügt es, lediglich für den WebClient „using System.Net“ einzubinden.

Quelltexte:

Python

#!/usr/bin/env python3
# -------------------------------
# SVG-Liniengrafik
# Datenvisualisierung mit Python
# Claus Brell
# 06.01.2024
# -------------------------------
# Ablauf:
#   Stage 1: Daten laden von Internetquelle
#   Stage 2: Daten umformen / anpassen
#   Stage 3: SVG-Grafik erzeugen
# -------------------------------
# Vorbereitungen
# -------------------------------
# Import für Internet-Zugriff
import requests
import sys
# initialisieren, sonst kann man nichts anhängen
# für die x-Achse
listeZeit=[]
listeZeitstempel=[]
# für die y-Achse
listeLeistung=[]
listeEnergie=[]
# --------------------------------
# SVG-Rohling festlegen
# --------------------------------
# polyLineErsatz wird die transformierten Daten aufnehmen
polyLineErsatz1=''
polyLineErsatz2=''
# mehrzeiliger String mit """
svgRahmen="""<svg width="800" height="400" viewBox="0 0 800 400" xmlns="http://www.w3.org/2000/svg">
<desc>Liniengrafik mit Daten aus 2024</desc>
<!-- x und y Achse           -->
<line x1="50" y1="350" x2="750" y2="350" stroke="#0a0a0a" stroke-width="2" />
<line x1="50" y1="350" x2="50" y2="50" stroke="#0a0a0a" stroke-width="2" />
<!-- Beschriftung -->
<!-- maximale Leistung -->
<text x="50" y="40" fill="#000000" font-size="16" text-anchor="middle">#*3*#W</text>
<!-- maximale Energie -->
<text x="#*4*#" y="40" fill="#ff0000" font-size="16" text-anchor="right">#*5*#kWh</text>
<!-- Startzeitpunkt -->
<text x="50" y="370" fill="#000000" font-size="16" text-anchor="left">#*6*#</text>
<!-- Endezeitpunkt -->
<text x="#*4*#" y="370" fill="#000000" font-size="16" text-anchor="right">#*7*#</text>
<!-- Polygonzug zeichnen     -->
<!-- für Leistung            -->
<polyline points="#*1*#" fill="none" stroke="black"/>
<!-- für Energie             -->
<polyline points="#*2*#" fill="none" stroke="red"/>
</svg>
"""
# ---------------------------------------
# Stage 1 Daten laden von Internetquelle
# (Daten Speichern wird hier aus didaktischen Gründen unerschlagen)
# ---------------------------------------
print('Stage 1 Daten von Internet-Quelle laden') # Nutzerbeglückung
print()

url='https://clabremo.de/shelly/WS/getshellycsvWS.php?shellyNr=192.168.1.81'
print("Aufruf :", url)                           # Nutzerbeglückung 
response = requests.get(url)
print("--> ",response)                      # Nutzerbeglückung
# -----------------------------------
# Daten in Listen
# -----------------------------------
# Rückgabeobjekt enthält den Inhalt der Internet-Ressource
# Daraus eine Liste von Zeilen erzeugen
datenstring=response.text
zeilen=datenstring.split("\r\n")
anzahlZeilen=len(zeilen)
print("Anzahl Zeilen: ",anzahlZeilen) # Nutzerbeglückung
# Jede Zeile in Datenfelder zerlegen und in separate Listen packen
# Start mit 1, da in Zeile 0 die Spaltenbezeichnungen stehen
zeileNr=1 
# Leider hat Python kein schönes for-Konzept, also while-Schleife verwenden
while zeileNr<(anzahlZeilen-1):
    werte=zeilen[zeileNr].split(';')
    # WARTUNG print(werte)
    # ACHTUNG: werte sind Strings, damit kann man nicht rechnen ...
    # also: in Ganzzahlen konvertieren mit int()
    listeZeitstempel.append(int(werte[2]))
    listeZeit.append(werte[3])       # Zeit lesbar, als String belassen
    listeLeistung.append(float(werte[4]))   
    listeEnergie.append(float(werte[5]))
    zeileNr=zeileNr+1
# Nutzerbeglückung: Einen Teil der Listen ausgeben
print('Ergebnis-Listen (Auszug)')
print('..............................')
print('Nr \t Zeit \t Leistung \t Energie')
zeileNr=0
while zeileNr<anzahlZeilen and zeileNr<10:
    print(zeileNr, '\t', listeZeit[zeileNr], '\t', listeLeistung[zeileNr], '\t', listeEnergie[zeileNr])
    zeileNr=zeileNr+1
zeileNr=anzahlZeilen-10
print('..............................')
while zeileNr<(anzahlZeilen-2):
    print(zeileNr, '\t', listeZeit[zeileNr], '\t', listeLeistung[zeileNr], '\t', listeEnergie[zeileNr])
    zeileNr=zeileNr+1
print ("Daten in Listen umkopiert.")

# ------------------------
# Stage 2 Daten umformen / anpassen
# ------------------------
# Es folgt ein mehrfach verketteter Dreisatz, um die Daten an den viewBox des SVG anzupassen
# viewBox="0 0 800 400"
# maximaler y-Wert: 50
# minimaler y-Wert: 400-50
# minimaler x-Wert: 50
# maximaler x-Wert: 800-50
yMin=50
yMax=350
yDelta=yMax-yMin
xMin=50
xMax=750
xDelta=xMax-xMin
# Aufbereiten der Daten, x-Werte müssen nur einmal umgerechnet werden
xZeitstempel=[]
yLeistung=[]
yEnergie=[]
# ein paar Hilfsdaten
maxZeitstempel=max(listeZeitstempel)
minZeitstempel=min(listeZeitstempel)
deltaZeitstempel=3*24*60*60 # drei Tage
maxLeistung=max(listeLeistung)
maxEnergie=max(listeEnergie)
print('maximale Leistung: ',maxLeistung,' Engergie geerntet: ',maxEnergie) # Nutzerbeglückung

# ------------------------------------------
# Die folgenden Zeilen enthalten die eigentliche
# "Magie" des Programms ...
# ------------------------------------------
zeileNr=1 
while zeileNr<(anzahlZeilen-2):
    xZeitstempel.append(xMin+int(round((listeZeitstempel[zeileNr]-minZeitstempel)/deltaZeitstempel*xDelta)))
    yLeistung.append(yMax-int(round(listeLeistung[zeileNr]/maxLeistung*yDelta)))
    yEnergie.append(yMax-int(round(listeEnergie[zeileNr]/maxEnergie*yDelta)))
    zeileNr=zeileNr+1
# Nutzerbeglückung: Einen Teil der Listen ausgeben
print('Daten-Umformung (Auszug)')
print('..............................')
print('Nr \t Zeit \t Leistung \t Energie')
zeileNr=0
while zeileNr<anzahlZeilen and zeileNr<10:
    print(zeileNr, '\t', xZeitstempel[zeileNr], '\t', yLeistung[zeileNr], '\t', yEnergie[zeileNr])
    zeileNr=zeileNr+1
zeileNr=anzahlZeilen-10
print('..............................')
while zeileNr<(anzahlZeilen-3):
    print(zeileNr, '\t', xZeitstempel[zeileNr], '\t', yLeistung[zeileNr], '\t', yEnergie[zeileNr])
    zeileNr=zeileNr+1
print ("Daten an SVG angepasst.")

# ------------------------
# Stage 3 svg modifizieren
# ------------------------
# für jeden Wert einen Punkt erzeugen
for i in range(1,anzahlZeilen-3):
    x_str=str(xZeitstempel[i])
    yL_str=str(yLeistung[i])
    yE_str=str(yEnergie[i])
    polyLineErsatz1+=x_str+","+yL_str+" \r\n"
    polyLineErsatz2+=x_str+","+yE_str+" \r\n"
    # Nutzerbeglückung sys.stdout.write('.')
print ()
# Kontrolle
# print ("polyline-Ersatz")
# print ("---------------")
# print (polyLineErsatz1)
# print (polyLineErsatz2)
# letzter Schritt: Platzhalter in svg ersetzen
svgOut=svgRahmen.replace("#*1*#",polyLineErsatz1)
svgOut=svgOut.replace("#*2*#",polyLineErsatz2)
svgOut=svgOut.replace("#*3*#",str(maxLeistung))
svgOut=svgOut.replace("#*4*#",str(max(xZeitstempel)))
svgOut=svgOut.replace("#*5*#",str(listeEnergie[anzahlZeilen-3]))
svgOut=svgOut.replace("#*6*#",listeZeit[1])
svgOut=svgOut.replace("#*7*#",listeZeit[anzahlZeilen-3])

# speichern
# Datei öffnen, String hineinschreiben, schließen
datei = open('liniengrafik.svg','w')
datei.write(svgOut)
datei.close()
print ("Daten in linengrafik.svg gespeichert")
print ("----- fertig -----")

Listing 1: Python Quelltext

C#

 

// Noch aus der Python-Datei: #!/usr/bin/env python3
// -------------------------------
// SVG-Liniengrafik
// Datenvisualisierung mit Python >>> Umsetzung in C# / Dot Net
// Claus Brell
// 06.01.2024 >>> 08.01.2024
// -------------------------------
// Ablauf:
//   Stage 1: Daten laden von Internetquelle
//   Stage 2: Daten umformen / anpassen
//   Stage 3: SVG-Grafik erzeugen
// -------------------------------
// Vorbereitungen
// -------------------------------
// using System;    //funktioniert auch so
// using System.IO; //funktioniert auch so
using System.Net; // entspricht Import für Internet-Zugriff
// Das Folgende braucht man in Python nicht ...
// ACHTUNG: Keinen expliziten namespace verwenden

class Program {
 static void Main(string[] args) {

// initialisieren, sonst kann man nichts anhängen
// für die x-Achse
// so gehts: List<double> wertedummy =new List<double>() {1,2,3,4,5,6}; // vorbelegen
List<string> listeZeit=new List<string>();
List<int> listeZeitstempel=new List<int>();
// für die y-Achse
List<double> listeLeistung=new List<double>();
List<double> listeEnergie=new List<double>();
// --------------------------------
// SVG-Rohling festlegen
// --------------------------------
// polyLineErsatz wird die transformierten Daten aufnehmen
string polyLineErsatz1="";
string polyLineErsatz2="";
// mehrzeiliger String mit (""" in Python), in Dot Net kein Problem
string svgRahmen=@"<svg width=""800"" height=""400"" viewBox=""0 0 800 400""
xmlns=""http://www.w3.org/2000/svg"">
<desc>Liniengrafik mit Daten aus 2024</desc>
<!-- x und y Achse           -->
<line x1=""50"" y1=""350"" x2=""750"" y2=""350"" stroke=""#0a0a0a"" stroke-width=""2"" />
<line x1=""50"" y1=""350"" x2=""50"" y2=""50"" stroke=""#0a0a0a"" stroke-width=""2"" />
<!-- Beschriftung -->
<!-- maximale Leistung -->
<text x=""50"" y=""40"" fill=""#000000"" font-size=""16"" text-anchor=""middle"">#*3*#W</text>
<!-- maximale Energie -->
<text x=""#*4*#"" y=""40"" fill=""#ff0000"" font-size=""16"" text-anchor=""right"">#*5*#kWh</text>
<!-- Startzeitpunkt -->
<text x=""50"" y=""370"" fill=""#000000"" font-size=""16"" text-anchor=""left"">#*6*#</text>
<!-- Endezeitpunkt -->
<text x=""#*4*#"" y=""370"" fill=""#000000"" font-size=""16"" text-anchor=""right"">#*7*#</text>
<!-- Polygonzug zeichnen     -->
<!-- für Leistung            -->
<polyline points=""#*1*#"" fill=""none"" stroke=""black""/>
<!-- für Energie             -->
<polyline points=""#*2*#"" fill=""none"" stroke=""red""/>
</svg>
";
// ---------------------------------------
// Stage 1 Daten laden von Internetquelle
// (Daten Speichern wird hier aus didaktischen Gründen unterschlagen)
// ---------------------------------------
Console.WriteLine("Stage 1 Daten von Internet-Quelle laden");// Nutzerbeglückung

string url="https://clabremo.de/shelly/WS/getshellycsvWS.php?shellyNr=192.168.1.81";
Console.WriteLine("Aufruf: "+url);                           // Nutzerbeglückung 
string response = "";
//Anlegen eines Webclients. Dieser übernimmt das Herunterladen der Daten.
// Lassen Sie sich durch die "Veraltet-Warnung" nicht verblüffen
WebClient myWebClient = new WebClient();
// Datenstrom zur URL aufmachen in zwei Schritten
// WARTUNG Console.WriteLine("Url: "+url);
Stream data=myWebClient.OpenRead(url);
StreamReader reader=new StreamReader(data);
// Kompletten Inhalt der Rückgabe in einen String einlesen
Console.Write("Beginne Daten Einlesen ...");
response=reader.ReadToEnd();
Console.Write("Einlesen beendet, Enter drücken (1) ...");
// WARTUNG Console.ReadLine();
// Verbindung wieder schließen
reader.Close();
data.Close();
Console.WriteLine("\r\nresponse: ");
Console.WriteLine(response.Substring(0,512)); 
Console.WriteLine(response.Substring(response.Length-512));                    // Nutzerbeglückung
// -----------------------------------
// Daten in Listen
// -----------------------------------
// Rückgabeobjekt enthält den Inhalt der Internet-Ressource
// Daraus eine Liste von Zeilen erzeugen
string[] zeilen=response.Split("\r\n"); // https://learn.microsoft.com/de-de/dotnet/api/system.string.split?view=net-8.0
int anzahlZeilen=zeilen.Length;
Console.Write("Anzahl Zeilen: "); // Nutzerbeglückung
Console.WriteLine(anzahlZeilen); // Nutzerbeglückung
// Jede Zeile in Datenfelder zerlegen und in separate Listen packen
// Start mit 1, da in Zeile 0 die Spaltenbezeichnungen stehen
int zeileNr=1; 
// Leider hat Python kein schönes for-Konzept, also while-Schleife verwenden
// Zum Vergleich hier vergleichbare Programmierung
Console.WriteLine("Umformung... Enter drücken (2) ...");
// WARTUNG Console.ReadLine();
while (zeileNr<(anzahlZeilen-1)){
    // WARTUNG Console.Write('.');
    string[] werte=zeilen[zeileNr].Split(';');
    // WARTUNG print(werte)
    // ACHTUNG: werte sind Strings, damit kann man nicht rechnen ...
    // also: in Ganzzahlen konvertieren mit int()
    listeZeitstempel.Add(Convert.ToInt32(werte[2])); //https://learn.microsoft.com/de-de/dotnet/api/system.convert.toint32?view=net-8.0
    listeZeit.Add(werte[3]);       // Zeit lesbar, als String belassen
    // ACHTUNG: eingedeutschtes DOT NET verwirft Punkt als Dezmaltrenner und rechnet falsch!!!!!
    listeLeistung.Add(Convert.ToDouble(werte[4].Replace(".",","))); // Korrigiert DOT NET Unsinn  
    listeEnergie.Add(Convert.ToDouble(werte[5].Replace(".",","))); // Korrigiert DOT NET Unsinn
    zeileNr++;
} // Ende while
// Nutzerbeglückung: Einen Teil der Listen ausgeben
Console.WriteLine("Ergebnis-Listen (Auszug) Enter drücken (3)");
// WARTUNG Console.ReadLine();
Console.WriteLine("..............................");
Console.WriteLine("Nr \t Zeit \t\t Leistung \t Energie");
zeileNr=0;
while(zeileNr<anzahlZeilen & zeileNr<10){
    Console.Write(zeileNr);
    Console.Write("\t");
    Console.Write(listeZeit[zeileNr]);
    Console.Write("\t");
    Console.Write(listeLeistung[zeileNr]);
    Console.Write("\t");
    Console.WriteLine(listeEnergie[zeileNr]);
    zeileNr++;
}
zeileNr=anzahlZeilen-10;
Console.WriteLine("..............................");
while (zeileNr<(anzahlZeilen-2)){
    Console.Write(zeileNr);
    Console.Write("\t");
    Console.Write(listeZeit[zeileNr]);
    Console.Write("\t");
    Console.Write(listeLeistung[zeileNr]);
    Console.Write("\t");
    Console.WriteLine(listeEnergie[zeileNr]);
    zeileNr++;
}
Console.WriteLine("Daten in Listen umkopiert.");

// ------------------------
// Stage 2 Daten umformen / anpassen
// ------------------------
// Es folgt ein mehrfach verketteter Dreisatz, um die Daten an den viewBox des SVG anzupassen
// viewBox="0 0 800 400"
// maximaler y-Wert: 50
// minimaler y-Wert: 400-50
// minimaler x-Wert: 50
// maximaler x-Wert: 800-50
int yMin=50;
int yMax=350;
int yDelta=yMax-yMin;
int xMin=50;
int xMax=750;
int xDelta=xMax-xMin;
// Aufbereiten der Daten, x-Werte müssen nur einmal umgerechnet werden
List<int> xZeitstempel=new List<int>();
List<int> yLeistung=new List<int>();
List<int> yEnergie=new List<int>();
// ein paar Hilfsdaten
int maxZeitstempel=listeZeitstempel.Max();
int minZeitstempel=listeZeitstempel.Min();
int deltaZeitstempel=3*24*60*60; // drei Tage
double maxLeistung=listeLeistung.Max();
double maxEnergie=listeEnergie.Max();
Console.Write("kleinster Zeitstempel: ");
Console.Write(minZeitstempel); // Nutzerbeglückung
Console.Write(" größter Zeitstempel: ");
Console.Write(maxZeitstempel); // Nutzerbeglückung
Console.Write(" Delta: ");
Console.WriteLine(deltaZeitstempel); // Nutzerbeglückung
Console.Write("erster Zeitstempel: ");
Console.Write(listeZeitstempel[0]); // Nutzerbeglückung
Console.Write(" letzter Zeitstempel: ");
Console.WriteLine(listeZeitstempel[anzahlZeilen-3]); // Nutzerbeglückung
Console.Write("maximale Leistung: ");
Console.Write(maxLeistung); // Nutzerbeglückung
Console.Write(" Energie geerntet: "); // Nutzerbeglückung
Console.WriteLine(maxEnergie); // Nutzerbeglückung
// ------------------------------------------
// Die folgenden Zeilen enthalten die eigentliche
// "Magie" des Programms ...
// ------------------------------------------
zeileNr=0;
while (zeileNr<(anzahlZeilen-2)){
    xZeitstempel.Add(xMin+(int)Math.Round((double)(listeZeitstempel[zeileNr]-minZeitstempel)/(double)deltaZeitstempel*(double)xDelta));
    yLeistung.Add(yMax-(int)Math.Round((double)(listeLeistung[zeileNr]/maxLeistung*yDelta)));
    yEnergie.Add(yMax-(int)Math.Round((double)(listeEnergie[zeileNr]/maxEnergie*yDelta)));
    // WARTUNG Console.WriteLine(zeileNr);
    // WARTUNG Console.WriteLine(xZeitstempel[zeileNr]);
    zeileNr++;
    
}
// Nutzerbeglückung: Einen Teil der Listen ausgeben
Console.WriteLine("\r\nDaten-Umformung (Auszug)");
Console.WriteLine("..............................");
Console.WriteLine("Nr \t Zeit \t Leistung \t Energie");
zeileNr=0;
while (zeileNr<anzahlZeilen & zeileNr<10){
    Console.Write(zeileNr);
    Console.Write('\t');
    Console.Write(xZeitstempel[zeileNr]);
    Console.Write('\t');
    Console.Write(yLeistung[zeileNr]);
    Console.Write('\t');
    Console.WriteLine(yEnergie[zeileNr]);
    zeileNr++;
}
zeileNr=anzahlZeilen-10;
Console.WriteLine("..............................");
while (zeileNr<(anzahlZeilen-3)){
    Console.Write(zeileNr);
    Console.Write('\t');
    Console.Write(xZeitstempel[zeileNr]);
    Console.Write('\t');
    Console.Write(yLeistung[zeileNr]);
    Console.Write('\t');
    Console.WriteLine(yEnergie[zeileNr]);    
    zeileNr++;
}
Console.WriteLine("Daten an SVG angepasst.");

// ------------------------
// Stage 3 svg modifizieren
// ------------------------
// für jeden Wert einen Punkt erzeugen
string x_str, yL_str, yE_str;
for (int i=1;i<(anzahlZeilen-3);i++){
    x_str=xZeitstempel[i].ToString();
    yL_str=yLeistung[i].ToString();
    yE_str=yEnergie[i].ToString();
    polyLineErsatz1+=x_str+","+yL_str+" \r\n";
    polyLineErsatz2+=x_str+","+yE_str+" \r\n";
    // Nutzerbeglückung sys.stdout.write('.')
}

// Kontrolle (noch Zeilen aus Python Programm)
// print ("polyline-Ersatz")
// print ("---------------")
// print (polyLineErsatz1)
// print (polyLineErsatz2)
// letzter Schritt: Platzhalter in svg ersetzen
string svgOut=svgRahmen.Replace("#*1*#",polyLineErsatz1);
svgOut=svgOut.Replace("#*2*#",polyLineErsatz2);
svgOut=svgOut.Replace("#*3*#",maxLeistung.ToString());
svgOut=svgOut.Replace("#*4*#",Convert.ToString(xZeitstempel.Max()-75)); // etwas nach links verschieben
svgOut=svgOut.Replace("#*5*#",Convert.ToString(listeEnergie[anzahlZeilen-3]));
svgOut=svgOut.Replace("#*6*#",listeZeit[1]);
svgOut=svgOut.Replace("#*7*#",listeZeit[anzahlZeilen-3]);
// speichern
// Datei öffnen, String hineinschreiben, schließen
// Das geht in C# einfacher als in Python
File.WriteAllText("liniengrafikDotNet.svg", svgOut); 
Console.WriteLine("Daten in liniengrafikDotNet.svg gespeichert");
Console.WriteLine("----- fertig -----");

 } // Ende main
}// Ende class
// Achtung: kein Ende namespace

Listing 3: C# Quelltext

 

Anhang

Quellen

SVG Grafiken erzeugen mit chatGPT

SVG Tutorials

Übersicht von Tutorials auf selfhtml: https://wiki.selfhtml.org/wiki/SVG/Tutorials

Ein HTML-Seminar, das SVG beleuchtet: https://www.html-seminar.de/svg-in-websites-nutzen.htm

Glossar

ETL-Prozess

Extract, Transform, Load (ETL) ist ein Prozess, bei dem Daten aus mehreren, oft unterschiedlich oder auch gar nicht strukturierten Datenquellen geladen, umgeformt und dann in einer Zieldatenbank – das kann auch eine einfache Datei sein – zusammengeführt werden. Eingesetzt werden ETL-Prozesse z.B. beim data-warehousing. Mittels ETL zusammengeführte Daten werde oft visualisiert, um sie einer schnellen Beurteilung zugänglich zu machen.

Autor und Lizenz

Autor: Prof. Dr. rer. nat. Claus Brell, aktuelle Projekte: Biene40AI4Bee
Lizenz: CC BY

Inhalte des Beitrages können Sie entsprechen der Lizenz verwenden. Unter dieser Lizenz veröffentlichte Werke darf jedermann für private, gewerbliche und sonstige Zwecke nutzen verändern und auch neu ohne CC-Lizenz vermarkten. Als Urheber mache ich keine Rechte geltend.

 

 

Teile diesen Beitrag.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert