Seite 1 von 1

Csv datei in Python als Grafik darstellen

Verfasst: Samstag 18. Januar 2020, 15:39
von Erensow
Sehr geehrter Damen und Herren,

ich habe leider ein kleines Problem.
Undzwar besteht meine Aufgabe dadrin, ein Phyton programm zu erstellen, dass die aktuellen Temperaturen von einer seite Downloadet und dies als Grafik wieder gibt.

Was ich bisher gemacht habe :

-------------------------------------------------------------------------------------------------------------------------------
#Temperatur Csv Download

from urllib.request import urlopen
url= ("https://www.lanuv.nrw.de/fileadmin/lanu ... T_AM1H.csv")
Dateiname = "Temperatur.csv"
with open (Dateiname, "wb") as datei:
datei.write(urlopen(url).read())

#Csv datei und matplotlib einbinden

import csv
import matplotlib.pyplot as plt

#CSV Datei Öffnen und in Phyton wiedergeben


with open("Temperatur.csv", encoding="ansi") as datei:
for zeile in csv.DictReader(datei, delimiter=";"):
print(zeile)

-------------------------------------------------------------------------------------------------------------------------------

Nun weiß ich leider nicht mehr weiter, wie ich diese Csv datei so umwandeln kann, das ich auf der X achse das Datum und auf der Y achse die Temperatur angezeigt bekomme.
Außerdem ist dies für 360 tage ... also wird der Graf unübersichtlich, daher wollte ich auch es so programmieren, das ich eingeben muss, das ich es nur für die ersten 7 tage Z.b den graf haben möchte....

Ich entschuldige mich direkt auch für diese fragen...

Mit freundlichen Grüßen.

Eren

Re: Csv datei in Python als Grafik darstellen

Verfasst: Montag 20. Januar 2020, 12:23
von DeaD_EyE
Mit pandas wäre das wahrscheinlich recht einfach.
Bei dem CSV-Modul muss man viel "zu Fuß" machen.

Daten können Fehler enthalten und die sind abzufangen.
Eine Eigenart, die mir aufgefallen ist, dass die offensichtlich auch die Uhrzeit 24:00 verwenden.
Das kann man nicht direkt mit datetime parsen.

Code: Alles auswählen

import csv
from datetime import datetime as dt
from datetime import timedelta as td
from urllib.request import urlopen

import matplotlib.pyplot as plt


url= "https://www.lanuv.nrw.de/fileadmin/lanuv/luft/temes/T_AM1H.csv"
dateiname = "Temperatur.csv"


with open (dateiname, "wb") as datei:
    req = urlopen(url)
    # nicht alles aufeinmal laden
    while True:
        chunk = req.read(64 * 1024)
        if not chunk:
            # keine Daten mehr, Datei zuende.
            break
        # Schreibe den block
        datei.write(chunk)


field = "BONN T AM1H [°C]"
dt_format = '%d.%m.%Y %H:%M'


with open("Temperatur.csv") as datei:
    next(datei)
    # datei ist ein Iterator
    # Im Header steht ein Kommentar, der zuerst verworfen werden muss
    # next(datei) gibt die aktuelle Zeile aus, die hier aber nicht verwnedet wird
    dict_reader = csv.DictReader(datei, delimiter=";")
    # der DictReader bekommt als erstes Argument das Dateiobjekt
    # dieser liest dann die erste Zeile mit den Feldnamen ein.
    # Da der Kommentar bereits übersprungen ist, funktioniert das
    dates = []
    values = []
    for row in dict_reader:
        value = row[field].replace(",", ".")
        if not value:
            # wenn kein Wert vorhanden ist,
            # dann überspringen
            continue
        
        datum = row["Datum"]
        zeit = row["Zeit"]
        # offensichtlich kommt auch 24 Uhr in den Datensätzen vor
        # das wäre dann schon der nächste Tag
        # 24:00 lässt sich aber nicht parsen
        # also setze ich das auf 00:00 und
        # füge einen Tag hinzu.
        if '24:00' == zeit:
          zeit = '00:00'
          next_day = True
        else:
          next_day = False
          
        zeitstempel =  datum + " " + zeit
        # Hier tritt ein Fehler auf, wenn die Zeitangabe
        # ungültig ist
        # ggf. mit try... except abfangen und überspringen
        zeitstempel = dt.strptime(zeitstempel, dt_format)

        # nächster Tag
        if next_day:
          zeitstempel += td(days=1)

        
        # Deutsch > Englisch
        # float("1,5") geht z.b. nicht
        # deswegen , durch . ersetzen

        # Wert auslesen und Komma durch Punkt ersetzen
        # Wert in float umwandeln
        # Bei der Umwandlung kann es zu einem ValueError
        # kommen, sofern der string nicht in einen float
        # umgewandelt werden kann
        # auch hier, kann man mit try und except den Fehler
        # abfangen und entsprechend reagieren.
        value = float(value)
        # wert zur Liste hinzufügen
        values.append(value)
        dates.append(zeitstempel)
        


plt.plot_date(dates, values, '-')
plt.show()


Re: Csv datei in Python als Grafik darstellen

Verfasst: Montag 20. Januar 2020, 16:21
von Sirius3
Muß die Datei auf der Platte zwischengespeichert werden? Man kann auch Direkt mit dem urlopen-Objekt weiter arbeiten.

@DeaD_EyE: datetime und timedelta sind Klassen, die man nicht kryptisch Abkürzen sollte.

Re: Csv datei in Python als Grafik darstellen

Verfasst: Mittwoch 29. Januar 2020, 01:27
von Erensow
Hallo:)
Erstmals danke für die schnelle antwort auf mein beitrag :)

Sie meinten es wäre mit pandas alles leichter?
Wie meinen sie das?

Ich brauche z. B für Bonn die Temperaturen und dies soll Matplotlip dann für die gewählte Tage ( das kann der User am Anfang aussuchen wie viel Tage der graf angezeigt werden soll)
Irgendwie kriege Ich das nicht hin.
Ich hoffe sie können mir mit pandas helfen.

Grüße :)

Re: Csv datei in Python als Grafik darstellen

Verfasst: Donnerstag 30. Januar 2020, 10:54
von DeaD_EyE
Sirius3 hat geschrieben: Montag 20. Januar 2020, 16:21 @DeaD_EyE: datetime und timedelta sind Klassen, die man nicht kryptisch Abkürzen sollte.
Nach dem 10 mal datetime.datetime.now, datetime.datetime.fromisoformat, datetime.timedelta gehen mir die Wiederholungen auf den Sack.
Vor allen dann, weil ich nicht für solche kleinen Sachen keine IDE verwende.

Außerdem kann es dazu führen, dass jemand danach fragt, was dieses from ... import foo as x überhaupt bedeutet.
Auch ein Lerneffekt ^^

Wenn der Code mehr als 100 Zeilen hat, ist das zu überblicken und mein Gehirn kann das noch so gerade eben verarbeiten.
Falls es mehr wird, steigt die Wahrscheinlichkeit, dass man dt und td irgendwas anderes zuweist.
Wenn das mal passiert, ist das auch gut. Nur wer Fehler macht, kann daraus lernen.
Mir ist schon klar, dass du es gerne so hättest, dass derjenige von Anfang an alles richtig lernt und sich keine schlechten Angewohnheiten verfestigen.

Bei anderen Modulen haben sich die Abkürzungen eingebürgert: numpy -> np, scipy -> sp, pandas -> pd, matplotlib.pyplot -> plt

Der OP hat nochmal die Frage gestellt, wie man Start- und Endzeitpunkt festlegen kann. Hier nochmal mein überarbeitetes Beispiel:

Code: Alles auswählen

import csv
import os
from datetime import datetime
from datetime import timedelta
from urllib.request import urlopen

import matplotlib.pyplot as plt


def chunked_download(url, dateiname):
  with open (dateiname, "wb") as datei:
      req = urlopen(url)
      # nicht alles aufeinmal laden
      while True:
          chunk = req.read(64 * 1024)
          if not chunk:
              # keine Daten mehr, Datei zuende.
              break
          # Schreibe den block
          datei.write(chunk)


def zeitstempel_umwandeln(datum, zeit):
    datetime_format = '%d.%m.%Y %H:%M'
    if '24:00' == zeit:
      zeit = '00:00'
      next_day = True
    else:
      next_day = False
    zeitstempel =  datum + " " + zeit
    zeitstempel = datetime.strptime(zeitstempel, datetime_format)
    if next_day:
      zeitstempel += timedelta(days=1)
    return zeitstempel


def werte_auslesen(dateiname, feld, start_datum, end_datum):
    x = []
    y = []
    with open(dateiname) as datei:
        next(datei) # 1. header überspringen
        dict_reader = csv.DictReader(datei, delimiter=";")
        for row in dict_reader:
            datum = row["Datum"]
            zeit = row["Zeit"]
            zeitstempel = zeitstempel_umwandeln(datum, zeit)
            if start_datum <= zeitstempel <= end_datum:
                wert = row[feld].replace(",", ".")
                if not wert:
                    continue
                wert = float(wert)
                x.append(zeitstempel)
                y.append(wert)
    return x, y


url = "https://www.lanuv.nrw.de/fileadmin/lanuv/luft/temes/T_AM1H.csv"
dateiname = "Temperatur.csv"
feld = "BONN T AM1H [°C]"


if not os.path.exists(dateiname):
    # nur herunterladen, falls die Datei fehlt
    # Das schont den Server
    # Sind nicht unsere Ressourcen
    chunked_download(url, dateiname)


start = datetime(2019, 1, 29)
ende = datetime(2020, 1, 30)
x, y = werte_auslesen(dateiname, feld, start, ende)

# Für Matplotlib gibt es viele
# Tutorials
# Docs: https://matplotlib.org/api/_as_gen/matplotlib.pyplot.plot.html#matplotlib.pyplot.plot
# Eigentlich soll man plt.plot und plt.plot_date nicht nutzen,
# sondern das objektorientierte Interface.
# Kommt daher, weil matplotlib an Matlab angelehnt ist.

plt.plot_date(x, y, '-')
plt.show()
Denkt euch für x und y was anderes aus. Üblicherweise schriebt man die Namen der Funktionen usw auch auf englisch.

Den Header, den ich mit next(datei) verwerfe, beinhaltet den Zeitraum: #ZEITBEREICH: 29.01.2019 bis 30.01.2020
Danach kommt der eigentliche Header mit den Feldnamen, den der DictReader automatisch liest.

Ich hoffe das ist den Herren jetzt so genehm.

Re: Csv datei in Python als Grafik darstellen

Verfasst: Donnerstag 30. Januar 2020, 11:59
von __blackjack__
@DeaD_EyE: Das Gegenteil von kryptischen Abkürzungen ist ja nicht immer alles voll auszuschreiben inklusive Modulnamen. Und auch den Lerneffekt mit dem ``as`` kann man ohne kryptische Abkürzungen erreichen. Zum Beispiel in dem man die Namen importiert und PEP8 konform umbenennt:

Code: Alles auswählen

from datetime import datetime as DateTime, timedelta as TimeDelta
Das IDE-Argument zieht IMHO nicht, weil jeder Editor der sich zum Programmieren eignet, mindestens Autovervollständigung für das was bereits im aktuellen oder allen offenen Dateien steht, anbietet. Wenn man also einmal `DateTime` voll ausgeschrieben hat, braucht man das nur noch anzufangen und kann es dann vom Editor vervollständigen lassen. Vernünftige Editoren machen die Vervollständigung auch so, dass man Vorschläge für beliebige Zeichen aus dem Wort in der richtigen Reihenfolge eingetippt, bekommt. Für `DateTime` brauche ich nur `DT` eintippen um hier gerade in diesem Beitragstext als ersten Vorschlag `DateTime` zu bekommen. Man kann also problemlos `dt` und `td` tippen und am Ende `DateTime` und `TimeDelta` im Text stehen haben. Das beste aus beiden Welten: die kryptischen Abkürzungen ohne Vokale die man früher gelernt/gewohnt war tippen, und die guten verständlichen Namen die man auch früher schon hätte schreiben sollen als Ergebnis. 😀

`chunked_download()` erfindet das Rad neu, denn es gibt in der Standardbibliothek `urllib.request.urlretrieve()` was genau das schon macht. Wobei es das Ergebnis von `urlopen()` auch schliesst.

Re: Csv datei in Python als Grafik darstellen

Verfasst: Donnerstag 30. Januar 2020, 14:02
von DeaD_EyE
Den vorgeschlagenen import finde ich hässlich. Besser wäre dann in Klammern.

Wenn, dann würde ich es so schreiben:

Code: Alles auswählen

from datetime import (
    datetime as DateTime,
    timedelta as TimeDelta,
)
Wer git kennt, weiß wieso.

Ich nutze sehr oft dumme Editoren für wenig Code, also zieht dein Argument nicht.
Ich weiß, dass diese Abkürzungen nicht aussagekräftig sind, wenn es mir aber Tipparbeit erspart, dann mache ich das so und werde mich dafür auch nicht 10 mal rechtfertigen.
Ich halte es z.B. für schädlich, wenn Anfänger eine IDE nutzen. Führt dazu, dass das Hirn faul wird und der Änfänger ohne IDE wie ein Ochse vorm Berg steht.

Das mit dem chunked_download kannte ich bis jetzt noch nicht.
Dann hoffe ich mal, dass ich das richtig implementiert habe :-D

Re: Csv datei in Python als Grafik darstellen

Verfasst: Donnerstag 30. Januar 2020, 14:34
von __blackjack__
@DeaD_EyE: Mein Argument zieht sehr wohl. Ich benutze für Python grundsätzlich keine IDE und so dumme Editoren gibt es heute nicht mehr. Wer unbedingt mit Notepad programmieren will hat selbst schuld. Syntaxhighlighting und Autovervollständigung kann heute jedes Programm das sich an Programmierer richtet, Editor nennt, und den Namen verdient.

Da der Import in eine Zeile passt in unter 80 Zeichen macht es keinen Sinn das auf mehrere Zeilen aufzuteilen. Sobald die Zeile 79 Zeichen überschritten hat wird es natürlich aufgeteilt auf einen Namen + eventuelle Umbenennung mit ``as`` pro Zeile. Und ich habe da auch keine Wahl und will die auch gar nicht haben, denn ich will mich damit nicht beschäftigen müssen → das macht mein Editor/das `black`-Plugin. Und `black` hat genau zwei Einstellungen: die maximale Zeilenlänge und ob ' in " umgewandelt werden sollen wenn der Code dadurch nicht länger wird oder nicht. Sind für meinen Geschmack sogar zwei Einstellungen zu viel, ich könnte auch mit 79 und Ja leben. 😀

Re: Csv datei in Python als Grafik darstellen

Verfasst: Donnerstag 30. Januar 2020, 14:42
von __deets__
Das Argument mit git kann ich durchaus verstehen. Darum mache ich imports auch ganz gerne so. Aber black & co sind mir in der Summe mehr wert.

Re: Csv datei in Python als Grafik darstellen

Verfasst: Donnerstag 30. Januar 2020, 14:49
von __blackjack__
Was die Implementierung von `chunked_download()` angeht: Wie gesagt wird `req` nicht geschlossen. Und natürlich ist `req` wieder ein schlechter Name, weil Abkürzungen eben so leicht falsch interpretiert werden können. Man könnte das zum Beispiel leicht als `request` missverstehen, was sicher nicht gemeint war, denn das Objekt ist ja keine Anfrage („request“) sondern eine Antwort („response“) vom Typ `http.client.HTTPResponse` wenn das URL-Schema HTTP(S) war. Wofür sollte `req` denn ausgeschrieben stehen?

Und die Schleife zum Inhalt von Dateiobjekten kopieren gibt es als `shutil.copyfileobj()` in der Standardbibliothek:

Code: Alles auswählen

def chunked_download(url, dateiname):
    with open(dateiname, "wb") as datei:
        with urlopen(url) as response:
            copyfileobj(response, datei)
Was `urlretrieve()` aus der Standardbibliothek noch zusätlich macht, ist schauen ob es den HTTP-Header „Content-Length“ in der Server-Antwort gibt und am Ende vergleichen ob die gelesene Länge mit der im Header angegebenen übereinstimmt. Falls der Server vorzeitig mit dem Senden aufgehört hat, bekommt man eine Ausnahme.

Re: Csv datei in Python als Grafik darstellen

Verfasst: Donnerstag 30. Januar 2020, 16:11
von Erensow
Hallo, ich hab dies nun weiter verarbeitet.

nun bekomme ich graphen für die jeweiligen Messwerte für bonn raus.

Heißt : Der Benutzer kann auswählen welche Messwert er haben möchte für Bonn

Nun will ich aber den Graphen nicht für 360 Tage sondern so, das der nutzer wählen kann wenn er z.b Messwert Temperatur gewählt hat, wie viele Tage er den Graphen haben möchte z.b für 7 tage ...
Also von 1 Tag bis 360 Tage...
Ich hoffe ihr könnt mir helfen
So weit bin ich :


import csv
from datetime import datetime as dt
from datetime import timedelta as td
from urllib.request import urlopen

import matplotlib.pyplot as plt

#Vorstellung
print("Grafische Darstellung von Wetterdaten \n"
f"--------------------------------------\n\n"
f"Dieses Programm erzeugt ein Diagramm mit\n"
"aktuellen Wetterdaten der letzten Tage für Bonn. \n"
f"Gib an, für welchen Messwert das Diagramm angezeigt werden \n"
f"soll und wie viele Tage berücksichtig werden sollen. \n\n"
f"Folgende Messwerte stehen zur Auswahl: \n\n"
f"\t Wetterdaten \n"
f"\t -----------\n\n"
f" 0) Temperatur \n"
f" 1) Relative Luftfeuchtigkeit \n"
f" 2) Windgeschwindigkeit \n"
f" 3) Windrichtung \n\n"
f"\t Schadstoffe \n"
f"\t -----------\n\n"
f" 4) Stickstoffmonoxid (NO)\n"
f" 5) Stickstoffdioxid (NO3)\n"
f" 6) Partikel PM10 \n")

#Input für User
Messwert = int(input("Gib die Kennziffer des gewünschten Messwertes ein: "))

#Solange Messwert nicht 0 - 6
while Messwert not in (range(0, 7)):
print("\nDiese Kenziffer existiert nicht. \n")
#Wiederholung wenn Messwert nicht 0 - 6
Messwert = int(input("Gib die Kennziffer des gewünschten Messwertes ein: "))
#---------------------------Temperatur-------------------------------------
if Messwert == 0:
url = ("https://www.lanuv.nrw.de/fileadmin/lanu ... T_AM1H.csv")
stadt = "BONN T AM1H [°C]"
dateiname = "Temperatur.csv"
print("\nSie haben die Auswertung für Messwert „Temperatur“ gewählt.")
#---------------------------Relative Luftfeuchtigkeit----------------------
elif Messwert == 1:
url = ("https://www.lanuv.nrw.de/fileadmin/lanu ... F_AM1H.csv")
stadt = "BONN F AM1H [%]"
dateiname = "RelativeLuftfeuchtigkeit.csv"
print("\nSie haben die Auswertung für Messwert „Relative Luftfeuchtigkeit“ gewählt.")
#---------------------------Windgeschwindigkeit----------------------------
elif Messwert == 2:
url = ("https://www.lanuv.nrw.de/fileadmin/lanu ... G_SM1H.csv")
stadt = "BONN WG SM1H [m/s]"
dateiname = "Windgeschwindigkeit.csv"
print("\nSie haben die Auswertung für Messwert „Windgeschwindigkeit“ gewählt.")
#---------------------------Windrichtung-----------------------------------
elif Messwert == 3:
url = ("https://www.lanuv.nrw.de/fileadmin/lanu ... R_VM1H.csv")
stadt = "BONN WR VM1H [°]"
dateiname = "Windrichtung.csv"
print("\nSie haben die Auswertung für Messwert „Windrichtung“ gewählt.")
#---------------------------Stickstoffmonoxid (NO)-------------------------
elif Messwert == 4:
url = ("https://www.lanuv.nrw.de/fileadmin/lanu ... O_AM1H.csv")
stadt ="BONN NO AM1H [µg/m³]"
dateiname = "Stickstoffmonoxid.csv"
print("\nSie haben die Auswertung für Messwert „Stickstoffmonoxid (NO)“ gewählt.")
#---------------------------Stickstoffdioxid (NO2)-------------------------
elif Messwert == 5:
url = ("https://www.lanuv.nrw.de/fileadmin/lanu ... 2_AM1H.csv")
stadt ="BONN NO2 AM1H [µg/m³]"
dateiname = "Stickstoffdioxid.csv"
print("\nSie haben die Auswertung für Messwert „Stickstoffdioxid (NO2)“ gewählt.")
#---------------------------Partikel PM10----------------------------------
elif Messwert == 6:
url = ("https://www.lanuv.nrw.de/fileadmin/lanu ... _GM24H.csv")
stadt ="BONN PM10F GM24H [µg/m³]"
dateiname = "Partikel.csv"
print("\nSie haben die Auswertung für Messwert „Partikel PM10“ gewählt.")

#If = wenn Messwert = 0 Temperatur ausführen
#elif = -> Oder (Fall unterscheidung)
#else wäre -> UND



with open (dateiname, "wb") as datei:
req = urlopen(url)
# nicht alles aufeinmal laden
while True:
chunk = req.read(64 * 1024)
if not chunk:
# keine Daten mehr, Datei zuende.
break
# Schreibe den block
datei.write(chunk)

dt_format = '%d.%m.%Y %H:%M'

with open(dateiname) as datei:
next(datei)
# next(datei) überspringen der 1. Zeile
zeile = csv.DictReader(datei, delimiter=";")
# der DictReader bekommt als erstes Argument das Dateiobjekt
# dieser liest dann die erste Zeile mit den Feldnamen ein.
# Da der Kommentar bereits übersprungen ist, funktioniert das
datumlist = []
wertlist = []
for row in zeile:
werte = row[stadt].replace(",", ".")
#Alle
if "<10" == werte:
werte = "5"
elif "<7" == werte:
werte = "3"
#da bei Stickstoffmonoxid und Partike PM10 "<10 und <7"
#auftauchen und nicht gefloutet werden können,
#ersetze <10 mit 5 und <7 mit 3
elif not werte:
# wenn kein Wert vorhanden ist (Leerzeile),
# dann überspringen
continue

datum = row["Datum"]
zeit = row["Zeit"]
# offensichtlich kommt auch 24 Uhr in den Datensätzen vor
# das wäre dann schon der nächste Tag
# 24:00 lässt sich aber nicht parsen
# also setze ich das auf 00:00 und
# füge einen Tag hinzu.
if '24:00' == zeit:
zeit = '00:00'
next_day = True
else:
next_day = False



zeitstempel = datum + " " + zeit
# Hier tritt ein Fehler auf, wenn die Zeitangabe
# ungültig ist
# ggf. mit try... except abfangen und überspringen
zeitstempel = dt.strptime(zeitstempel, dt_format)

# nächster Tag
if next_day:
zeitstempel += td(days=1)


# Deutsch > Englisch
# float("1,5") geht z.b. nicht
# deswegen , durch . ersetzen

# Wert auslesen und Komma durch Punkt ersetzen
# Wert in float umwandeln
# Bei der Umwandlung kann es zu einem ValueError
# kommen, sofern der string nicht in einen float
# umgewandelt werden kann
# auch hier, kann man mit try und except den Fehler
# abfangen und entsprechend reagieren.
werte = float(werte)
# wert zur Liste hinzufügen
wertlist.append(werte)
datumlist.append(zeitstempel)



plt.plot_date(datumlist, wertlist,'-')
plt.show()

Re: Csv datei in Python als Grafik darstellen

Verfasst: Freitag 31. Januar 2020, 13:00
von DeaD_EyE
Bitte nochmal den ganzen Code in Code-Tags setzen, da ansonsten alle Leerzeichen fehlen.

Re: Csv datei in Python als Grafik darstellen

Verfasst: Freitag 31. Januar 2020, 17:57
von Erensow
Ich hab es bisschen weiter verarbeitet. und den graph übersichtlicher gemacht.
Brauche jetzt wie gesagt : Der User soll nun nach dem aussuchen des Messwertes, die Tage auswählen können, die er geplottet bekommen soll..

Da weiß ich leider auch nicht weiter.

Außerdem muss ich noch Valueerror beim eintippen eines NICHT INTIGERS ( Buchstaben, in den Messwert = Int(input..) beheben, dort bin ich auch noch nicht weiter gekomen

Code: Alles auswählen

import csv
import matplotlib.dates as md
import matplotlib.ticker as mt
#Zeit angaben
from datetime import datetime as dt
from datetime import timedelta as td
#Downloaden der CSV datei
from urllib.request import urlopen
#Für Random Zahl
from random import *
#Matplotlib
import matplotlib.pyplot as plt

#Vorstellung
print("Grafische Darstellung von Wetterdaten \n"
      f"--------------------------------------\n\n"
      f"Dieses Programm erzeugt ein Diagramm mit\n"
      "aktuellen Wetterdaten der letzten Tage für Bonn. \n"
      f"Gib an, für welchen Messwert das Diagramm angezeigt werden \n"
      f"soll und wie viele Tage berücksichtig werden sollen. \n\n"
      f"Folgende Messwerte stehen zur Auswahl: \n\n"
      f"\t Wetterdaten \n"
      f"\t -----------\n\n"
      f"  0) Temperatur \n"
      f"  1) Relative Luftfeuchtigkeit \n"
      f"  2) Windgeschwindigkeit \n"
      f"  3) Windrichtung \n\n"
      f"\t Schadstoffe \n"
      f"\t -----------\n\n"
      f"  4) Stickstoffmonoxid (NO)\n"
      f"  5) Stickstoffdioxid (NO3)\n"
      f"  6) Partikel PM10 \n")

#Input für User
#int = Integer -> NUR ZAHL
try:
   Messwert = int(input("Gib die Kennziffer des gewünschten Messwertes ein: "))
except(ValueError):
      print("\nDies ist leider keine Kennziffer. \n")
      Messwert = int(input("Gib die Kennziffer des gewünschten Messwertes ein: "))


#Solange Messwert nicht 0 - 6       
while Messwert not in (range(0, 7)):
   print("\nDiese Kenziffer existiert nicht. \n")
   
#Wiederholung wenn Messwert nicht 0 - 6
   Messwert = int(input("Gib die Kennziffer des gewünschten Messwertes ein: "))
#---------------------------Temperatur-------------------------------------
if Messwert == 0:
   url = ("https://www.lanuv.nrw.de/fileadmin/lanuv/luft/temes/T_AM1H.csv")
   stadt = "BONN T AM1H [°C]"
   dateiname = "Temperatur.csv"
   labelname = "Temperatur"
   MesswertEinheit = "Messwert in °C"
   print("\nSie haben die Auswertung für Messwert „Temperatur“ gewählt.")
#---------------------------Relative Luftfeuchtigkeit---------------------- 
elif Messwert == 1:
    url = ("https://www.lanuv.nrw.de/fileadmin/lanuv/luft/temes/F_AM1H.csv")
    stadt = "BONN F AM1H [%]"
    dateiname = "RelativeLuftfeuchtigkeit.csv"
    labelname = "Relative Luftfeuchtigkeit"
    MesswertEinheit = "Messwert in °C"
    print("\nSie haben die Auswertung für Messwert „Relative Luftfeuchtigkeit“ gewählt.")
#---------------------------Windgeschwindigkeit----------------------------     
elif Messwert == 2:
    url = ("https://www.lanuv.nrw.de/fileadmin/lanuv/luft/temes/WG_SM1H.csv")
    stadt = "BONN WG SM1H [m/s]"
    dateiname = "Windgeschwindigkeit.csv"
    labelname ="Windgeschwindigkeit"
    MesswertEinheit = "Messwert in m/s"
    print("\nSie haben die Auswertung für Messwert „Windgeschwindigkeit“ gewählt.")
#---------------------------Windrichtung-----------------------------------     
elif Messwert == 3:
    url = ("https://www.lanuv.nrw.de/fileadmin/lanuv/luft/temes/WR_VM1H.csv")
    stadt = "BONN WR VM1H [°]"
    dateiname = "Windrichtung.csv"
    labelname ="Windrichtung"
    MesswertEinheit = "Messwert"
    print("\nSie haben die Auswertung für Messwert „Windrichtung“ gewählt.")
#---------------------------Stickstoffmonoxid (NO)-------------------------   
elif Messwert == 4:
    url = ("https://www.lanuv.nrw.de/fileadmin/lanuv/luft/temes/NO_AM1H.csv")
    stadt ="BONN NO AM1H [µg/m³]"
    dateiname = "Stickstoffmonoxid.csv"
    labelname ="Stickstoffmonoxid (NO)"
    MesswertEinheit = "Messwert in µg/m³"
    print("\nSie haben die Auswertung für Messwert „Stickstoffmonoxid (NO)“ gewählt.")
#---------------------------Stickstoffdioxid (NO2)-------------------------    
elif Messwert == 5:
    url = ("https://www.lanuv.nrw.de/fileadmin/lanuv/luft/temes/NO2_AM1H.csv")
    stadt ="BONN NO2 AM1H [µg/m³]"
    dateiname = "Stickstoffdioxid.csv"
    labelname ="Stickstoffdioxid (NO2)"
    MesswertEinheit = "Messwert in µg/m³"
    print("\nSie haben die Auswertung für Messwert „Stickstoffdioxid (NO2)“ gewählt.")
#---------------------------Partikel PM10----------------------------------     
elif Messwert == 6:
    url = ("https://www.lanuv.nrw.de/fileadmin/lanuv/luft/temes/PM10F_GM24H.csv")
    stadt ="BONN PM10F GM24H [µg/m³]"
    dateiname = "Partikel.csv"
    labelname ="Partikel PM10"
    MesswertEinheit = "Messwert in µg/m³"
    print("\nSie haben die Auswertung für Messwert „Partikel PM10“ gewählt.")

#If = wenn Messwert = 0 Temperatur ausführen
#elif  =  -> Oder (Fall unterscheidung)
#else wäre ->  UND


#CSV-Datei herunterladen
with open(dateiname, "wb") as datei:
   datei.write(urlopen(url).read())

with open(dateiname, encoding="ansi") as datei:
    next(datei)
    # next(datei) überspringen der 1. Zeile 
    zeile = csv.DictReader(datei, delimiter=";")
    # dieser liest dann die erste Zeile mit den Feldnamen ein.
    datumlist = []
    wertlist = []
    for row in zeile:
        werte = row[stadt].replace(",", ".")
        #Alle
        if "<10" == werte:
            werte = randint(0,9)
        elif "<7" == werte:
            werte = randint(0,6)
        #da bei Stickstoffmonoxid und Partike PM10 "<10 und <7"
        #auftauchen und nicht gefloutet werden können,
        #ersetze <10 mit einer Zufälligen Zahl zwischen 0 - 10
        #und <7 mit einer Zufälligen Zahl zwischen 0 - 6
        elif not werte:
           werte == 0
            # wenn kein Wert vorhanden ist,
            # dann = 0 setzen
           continue
            
        
        datum = row["Datum"]
        zeit = row["Zeit"]
        #Da wir 24:00 uhr schon der nächste Tag ist,
        #Setzte ich es zu 00:00
        if '24:00' == zeit:
          zeit = '00:00'
          next_day = True
        else:
          next_day = False

        
          
        zeitstempel =  datum + " " + zeit
        #Datum und Zeit werden in einer einzigen Zeitangabe
        #zusammengebaut -> numerischen Datumswert ungeformt
        zeitstempel = dt.strptime(zeitstempel, '%d.%m.%Y %H:%M')

        # nächster Tag
        if next_day:
          zeitstempel += td(days=1)

        werte = float(werte)
        # wert zur Liste hinzufügen
        wertlist.append(werte)
        datumlist.append(zeitstempel)
        
# Größe auf dem Bildschirm vorgeben, hier ungefähr 8 mal 6 Zoll:
fig, ax = plt.subplots(figsize=(10,6))
# Überschrift:
plt.title(labelname)

# Messkurve, mit Label für Legende, einzeichnen:
plt.plot(datumlist, wertlist, label=labelname )
plt.xlabel("Datum")
plt.ylabel(MesswertEinheit)
# Die gewünschte Datumsformatierung der x-Achse definieren.
ax.xaxis.set_major_formatter(md.DateFormatter("%d.%m.%Y"))


# Für die untergeordneten Teilstriche kann man zusätzlich eine „minor“
# Formatierung festlegen.
# Diese Teilstriche sollen hier beispielsweise 0.5°C auflösen.
ax.yaxis.set_minor_locator(mt.MultipleLocator(0.5))

# Datumsbeschriftung der x-Achse um 30° drehen:
fig.autofmt_xdate(rotation=30)

# Den überflüssigen Freiraum vor und hinter der Diagrammkurve abschneiden:
plt.xlim(datumlist[0],datumlist[-1])

# Ein Raster erleichtert das Ablesen.
plt.grid(color="lightgrey")

# Eine Legende hinzufügen:
plt.legend()

# Vorhandenen Platz optimal ausnutzen, unnötige Ränder entfernen,
# Überlappen von Grafikelementen verhindern:
plt.tight_layout()

# Zeigt Plot an
plt.show()


Re: Csv datei in Python als Grafik darstellen

Verfasst: Samstag 1. Februar 2020, 13:31
von Sirius3
Jetzt hast Du ja noch mehr kryptische zweibuchstabige Abkürzungen, mt, md, dt, td da kann man sich leicht mal vertippen. Um so mehr, dass man damit exakt einmal sich ein paar Tasten spart.
Keine *-Importe sondern immer nur explizit. Eingerückt wird immer mit 4 Leerzeichen pro Ebene, nicht mal 2 oder 3.
Dann vertragen die 200 Zeilen ein paar Funktionsdefinitionen. Namenskonvention für Variablen ist klein_mit_unterstrich: messwert_einheit
Die ganzen f-Strings haben keine Formatangaben.
Kodewiederholungen vermeiden: Du hast dreimal die identische Zeile »Messwert = ...«, statt dessen solltest Du eine while-True-Schleife benutzen und diese bei korrekter Eingabe verlassen. ›except‹ ist keine Funktion, da braucht es keine Klammern.
Die lange if-elif-Kaskade solltest Du doch eine passende Datenstruktur ersetzen.

Verbindungen, die man mit urlopen öffnet, sollte man auch wieder schließen.
Typenbezeichner sollten nicht in Variablennamen vorkommen, also `werte` statt `wertlist`, wobei dann später die Variable `werte` für einen Wert natürlich auch repariert werden muß.
`zeile` für viele Zeilen ist dann wiederum andersherum falsch.
Beim Plotten nutzt Du plt statt fig bzw. ax.

Re: Csv datei in Python als Grafik darstellen

Verfasst: Dienstag 4. Februar 2020, 10:52
von Erensow
Danke für die Infos:)
Dies löst aber trz meine Frage nicht 😣

Re: Csv datei in Python als Grafik darstellen

Verfasst: Dienstag 4. Februar 2020, 11:18
von Sirius3
Wenn Du Dein Programm aufgeräumt hast, dann ist es einfach, das an der richtigen Stelle zu fixen.

Re: Csv datei in Python als Grafik darstellen

Verfasst: Dienstag 4. Februar 2020, 12:11
von marvo
Ganz herzlichen Dank an DeaD_EyE, Sirius3 und __blackjack__ für das geduldige Beantworten der Fragen zu der von mir gestellten Hausaufgabe :-)

Liebe mitlesende Studierende, vergesst bitte nicht, in der Dokumentation eine ordentliche Quellenangabe vorzunehmen!

Re: Csv datei in Python als Grafik darstellen

Verfasst: Dienstag 4. Februar 2020, 12:20
von __deets__
😆👏🙇‍♂️

Re: Csv datei in Python als Grafik darstellen

Verfasst: Donnerstag 6. Februar 2020, 13:37
von __blackjack__
Was glaube ich noch nicht erwähnt wurde ist das "ansi" eine ungünstige Wahl als Kodierung ist, denn das funktioniert nur unter Windows, und ich sehe nicht warum man das nicht so schreiben sollte, dass es auch unter Linux, MacOS, … laufen kann.

Hier mal eine überarbeitete Version:

Code: Alles auswählen

#!/usr/bin/env python3
import csv
import os
from collections import namedtuple
from datetime import datetime as DateTime, timedelta as TimeDelta
from random import randrange
from urllib.request import urlretrieve

from matplotlib import pyplot as plt
from matplotlib.dates import DateFormatter
from matplotlib.ticker import MultipleLocator

BASE_URL = "https://www.lanuv.nrw.de/fileadmin/lanuv/luft/temes/"


MeasurementDescription = namedtuple(
    "MeasurementDescription",
    "name remote_filename column_name local_filename unit",
)

MEASUREMENT_DESCRIPTIONS = [
    MeasurementDescription(
        "Temperatur", "T_AM1H.csv", "BONN T AM1H [°C]", "Temperatur.csv", "°C"
    ),
    MeasurementDescription(
        "Relative Luftfeuchtigkeit",
        "F_AM1H.csv",
        "BONN F AM1H [%]",
        "RelativeLuftfeuchtigkeit.csv",
        "%",
    ),
    MeasurementDescription(
        "Windgeschwindigkeit",
        "WG_SM1H.csv",
        "BONN WG SM1H [m/s]",
        "Windgeschwindigkeit.csv",
        "m/s",
    ),
    MeasurementDescription(
        "Windrichtung",
        "WR_VM1H.csv",
        "BONN WR VM1H [°]",
        "Windrichtung.csv",
        "°",
    ),
    MeasurementDescription(
        "Stickstoffmonoxid (NO)",
        "NO_AM1H.csv",
        "BONN NO AM1H [µg/m³]",
        "Stickstoffmonoxid.csv",
        "µg/m³",
    ),
    MeasurementDescription(
        "Stickstoffdioxid (NO2)",
        "NO2_AM1H.csv",
        "BONN NO2 AM1H [µg/m³]",
        "Stickstoffdioxid.csv",
        "µg/m³",
    ),
    MeasurementDescription(
        "Partikel PM10",
        "PM10F_GM24H.csv",
        "BONN PM10F GM24H [µg/m³]",
        "Partikel.csv",
        "µg/m³",
    ),
]


def ask_for_measurement_description():
    print(
        "Grafische Darstellung von Wetterdaten \n"
        "--------------------------------------\n\n"
        "Dieses Programm erzeugt ein Diagramm mit\n"
        "aktuellen Wetterdaten der letzten Tage für Bonn.\n"
        "Gib an, für welchen Messwert das Diagramm angezeigt werden\n"
        "soll und wie viele Tage berücksichtig werden sollen.\n\n"
        "Folgende Messwerte stehen zur Auswahl:\n"
    )
    for i, description in enumerate(MEASUREMENT_DESCRIPTIONS):
        print(f"{i:>3}) {description.name}")
    print()
    while True:
        try:
            index = int(
                input("Gib die Kennziffer des gewünschten Messwertes ein: ")
            )
        except ValueError:
            print("\nDies ist leider keine Kennziffer. \n")
        else:
            if 0 <= index < len(MEASUREMENT_DESCRIPTIONS):
                description = MEASUREMENT_DESCRIPTIONS[index]
                print(
                    f"\nSie haben die Auswertung für Messwert"
                    f" „{description.name}“ gewählt."
                )
                return description
            print("\nDiese Kenziffer existiert nicht. \n")


def parse_value(string):
    string = string.strip().replace(",", ".")
    if not string:
        return None
    #
    # Da bei Stickstoffmonoxid und Partikel PM10 "<10" und "<7"
    # auftauchen und nicht gefloutet werden können, ersetze "<n" mit
    # einer zufälligen Zahl zwischen 0 und n-1.
    #
    return (
        randrange(int(string[1:])) if string.startswith("<") else float(string)
    )


def parse_timestamp(date_string, time_string):
    #
    # Statt 00:00 Uhr gibt es 24:00 Uhr was 00:00 Uhr am nächsten
    # Tag entspricht.
    #
    date_needs_adjustment = time_string == "24:00"
    if date_needs_adjustment:
        time_string = "00:00"

    timestamp = DateTime.strptime(
        f"{date_string} {time_string}", "%d.%m.%Y %H:%M"
    )

    if date_needs_adjustment:
        timestamp += TimeDelta(days=1)

    return timestamp


def load_data(filename, column_name):
    with open(filename, encoding="latin-1") as datei:
        next(datei)  # Kommentarzeile am Dateianfang überspringen.
        timestamps = list()
        values = list()
        for row in csv.DictReader(datei, delimiter=";"):
            value = parse_value(row[column_name])
            if value is not None:
                timestamps.append(parse_timestamp(row["Datum"], row["Zeit"]))
                values.append(value)

    assert len(values) == len(timestamps)
    return timestamps, values


def plot_data(timestamps, values, title, unit):
    figure, axes = plt.subplots(figsize=(10, 6))
    plt.title(title)
    plt.plot(timestamps, values, label=title)
    plt.xlabel("Datum")
    plt.ylabel(f"Messwerte in {unit}")
    axes.xaxis.set_major_formatter(DateFormatter("%d.%m.%Y"))
    axes.yaxis.set_minor_locator(MultipleLocator(0.5))
    figure.autofmt_xdate(rotation=30)
    plt.xlim(timestamps[0], timestamps[-1])
    plt.grid(color="lightgrey")
    plt.legend()
    plt.tight_layout()
    plt.show()


def main():
    description = ask_for_measurement_description()

    if not os.path.exists(description.local_filename):
        urlretrieve(
            BASE_URL + description.remote_filename, description.local_filename
        )

    timestamps, values = load_data(
        description.local_filename, description.column_name
    )
    plot_data(timestamps, values, description.name, description.unit)


if __name__ == "__main__":
    main()
Das die "<n" Angaben durch eine zufällige *ganze* Zahl ersetzt werden finde ich komisch.

Die `MeasurementDescription` sind auch recht redundant aufgebaut. Der Dateiname vom Server kommt im Spaltennamen vor und die Einheit auch. Da könnte man beispielsweise den Spaltennamen aus Dateiname auf dem Server und Einheit berechnen.