Durch Eingabe erstelltes Diagramm

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Olsen
User
Beiträge: 17
Registriert: Donnerstag 16. Oktober 2014, 17:46

Hallo zusammen,
ich brauche Hilfe/Ideen bei der Umsetzung folgendes Programms:

Über eine Benutzereingabe sollen mehrere darzustellende Kurven dargestellt werden. (matplotlib)
Ich habe bereits Listen fürs Datum (x-Werte) und die jeweiligen Listen für die Zahlen (y-Werte) . Es sollen jedoch nur die Kurven dargestellt werden die zuvor durch den Benutzer eingegeben worden sind.

Nehmen wir mal an es liegen Bevölkerungszahlen von allen Ländern dieser Welt vor, dann sollte der Programmablauf in etwa wie folgt sein.
Die Zahlen habe ich aus einer CSV-Datei in Listen eingelesen. Eine fürs Datum und je eine für jedes Land.
Nun gibt der Benutzer seine gewünschten Länder an die Mittels Matplotlib als Diagramm dargestellt werden sollen.

Ich weiß nun nicht wie ich dem Programm klar machen soll, dass es nur die zuvor durch den Benutzer eingegebenen Zahlen darstellt.

Vielen Dank im vorraus
Olsen
Benutzeravatar
__blackjack__
User
Beiträge: 13202
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Olsen: Ohne Code kann man da pauschal recht wenig zu sagen.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
NPC
User
Beiträge: 54
Registriert: Dienstag 8. Januar 2019, 17:51

@Olsen

Wenn ich dich richtig verstehe hast du eine CSV- Datei mit folgendem Aufbau: <Datum>; <Land 1>; <Land 2>; ...
Wenn du mir nun die Daten für <Land 1> geben sollst, dann wirst du dir die Spaltennamen durchlesen und nachsehen, welche Spalte zu <Land 1> gehört.
Und anschließend wirst du mir diese Spalte als Daten zurückgeben. Dein Programm soll nun einfach genau das selbe tun...
Wenn ich deinen Beitrag richtig verstehe, dann ist das einlesen der CSV-Datei ja kein Problem...
Somit sollte sich das Problem eigentlich auf eine if abfrage sowie eine schleife reduzieren.
Für mehr Hilfe bräuchte man allerdings, wie __blackjack__ sagt, den Code

Hoffe es hift dir
NPC
Olsen
User
Beiträge: 17
Registriert: Donnerstag 16. Oktober 2014, 17:46

Ist mit Sicherheit keine elegante Lösung bis dato. :D

Ich speicher den input in einer Liste da ich nicht weiß wie man sonst beliebig viele Benutzereingaben entgegen nehmen kann. Kann man das so machen?
Der Benutzer soll durch Kürzel beliebig viele Länder eingeben (DE, FR, usw).
Die Belkörungsdaten sind in Länderdaten gespeichert und es lässt sich über den Index darauf zugreifen
Am Ende soll das Prgramm die gewünschten Länder als Kurve darstellen. (matplot Teil ist noch nicht geschrieben) Da weiß ich auch noch nicht wie ich das machen soll ohne viel Schreibarbeit, jemand Tipps?

PS: Ist es ein Fehler die erste Zeile der CSV-Datei zu überspringen? Dort stehen die Kürzel für die Länder für die jeweilige Spalte. Vielleicht kann ich das ja irgendwie nutzen.


Code: Alles auswählen

Ländereingabe = str(input("""Geben Sie die Länder getrennt durch ein Leerzeichen ein: 
"""))

Länderwahl = Ländereingabe.split(" ")

dateihandler = open("Bevölkerung.csv")
for n in range(1):
    next(dateihandler)

inhalt = dateihandler.read()

zeilen = inhalt.rstrip().split("\n")

tabelle = []
Länderdaten = []

for zeile in range(len(zeilen)):
    spalten = zeilen[zeile].split(",")
    tabelle.append(spalten)
    tabelle[zeile][1:] = [int(zahl) for zahl in tabelle[zeile][1:]]

Datum = [zeile[0][:10] for zeile in tabelle]

def Datensammler(a):
    b = [zeile[a + 1] for zeile in tabelle]
    return b

for n in range(165):
    Länderdaten.append(Datensammler(n))
Sirius3
User
Beiträge: 17797
Registriert: Sonntag 21. Oktober 2012, 17:20

Zum Lesen von csv-Daten gibt es das csv-Modul, oder hier vielleicht noch passender pandas.read_csv. Damit wird der ganze Code zum Einzeiler.
Benutzeravatar
__blackjack__
User
Beiträge: 13202
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Olsen: Das ``for n in range(1):`` macht keinen Sinn. Eine Schleife die genau *einmal* durchlaufen wird, ist keine Schleife.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase). Funktions- und Methodennamen bezeichnen die Tätigkeit die von der Funktion oder Methode durchgeführt wird. `Datensammler()` ist aber keine Tätigkeit.

``for zeile in range(len(zeilen)):`` ist in Python ein „anti pattern“. Man kann direkt über die Elemente von Sequenztypen wie Listen iterieren, da braucht man keinen Umweg über einen Laufindex. `zeile` ist deshalb hier auch ein bisschen irreführend als Name, denn das ist ja gar keine Zeile sondern der Index einer Zeile.

`dateihandler` ist auch falsch. In anderen Sprachen ist `dateihandle` üblich wenn dort Dateien durch ”magische” Werte repräsentiert werden, die man an Funktionen übergibt. In Python ist das ein Dateiobjekt mit Methoden, also einfach `datei`.

Dateien sollte man wo möglich mit der ``with``-Anweisung öffnen. Und bei Textdateien die Kodierung explizit angeben.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
NPC
User
Beiträge: 54
Registriert: Dienstag 8. Januar 2019, 17:51

Olsen,

naja nachdem du selbst die Kürzel nutzen willst um die Länder zu ermitteln, wäre es gut wenn das Programm auch die Informationen hätte, wie die Daten und länder zusammen hängen. Daher ja die erste Zeile ist, zumindest meiner Meinung nach, wichtig, wenn dort die Kürzel zu den Daten drinnen stehen.
Je nachdem wie das Programm verwendet wird könnte man die Daten zuerst aus der CSV in Dicts laden und mit den Kürzeln so die Daten dann zuordnen. (Bietet sich dann auch für Matplotlib an (für legenden....))

@__blackjack__ sorry, dass ich jetzt so doof frage (ist aber ernst gemeint). Ich hatte früher mal gelesen, dass man die Dateien mit einem try-finally Block öffnen/bearbeiten soll. Der with block macht das selbe oder (bzw. fast, da vermutlich die __del__ methode des geöffneten docs aufgerufen wird)? Gibt es hier einen bevorzugten Fall für beide Varianten oder ist mit dem with statement aufgrund der Leserlichkeit dieser (fast) immer vorzuziehen?
Sirius3
User
Beiträge: 17797
Registriert: Sonntag 21. Oktober 2012, 17:20

@NPC: der with-Block ruft ein __enter__ und __exit__ des (File-)Objekts auf, kein __del__. In __exit__ wird die Datei geschlossen. Da es viel einfacher und klarer ist, ist with einem finally-Block vorzuziehen, weil man zusätzlich auch mit der __enter__ und __exit__-Methode flexibler ist.
Benutzeravatar
__blackjack__
User
Beiträge: 13202
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@NPC: ``try``/``finally`` musste man vor ``with`` verwenden um den gleichen/ähnlichen Effekt zu erzielen.

Code: Alles auswählen

    #
    # Früher:
    #
    file = open("test.txt", encoding="utf-8")
    try:
        ...
    finally:
        file.close()

    #
    # Jetzt:
    #
    with open("test.txt", encoding="utf-8") as file:
        ...

    #
    # Entspricht ungefähr:
    #
    context_manager = open("test.txt", encoding="utf-8")
    try:
        file = context_manager.__enter__()
        ...
    finally:
        file.__exit__(*sys.exc_info())
In dem Fall sind `file` und `context_manager` das gleiche Objekt weil die `__enter__()`-Methode von den Objekten die `open()` liefert einfach nur `self` zurück gibt. Das muss aber nicht sein. Es können da auch andere Objekte zurückgegeben werden die dann eine `__exit__()`-Methode haben in der am Ende des ``with``-Blocks dann irgend etwas gemacht macht. Bei Dateiobjekten ist das sehr wahrscheinlich einfach `self.close()`.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
NPC
User
Beiträge: 54
Registriert: Dienstag 8. Januar 2019, 17:51

@Sirius3 & @__blackjack__,
danke für die Antworten :).

@Olsen sorry, dass ich den Thead kurz gekapert habe.
Olsen
User
Beiträge: 17
Registriert: Donnerstag 16. Oktober 2014, 17:46

@NPC kein Problem. Versuche mich gerade in Pandas einzuarbeiten um zu schauen ob es damit besser klappt.
Olsen
User
Beiträge: 17
Registriert: Donnerstag 16. Oktober 2014, 17:46

@Sirius3 vielen Danke für den Tipp mit Pandas. Damit klappt es wunderbar. Bin nun auf ein anderes Problem gestoßen:

Der Benutzer soll den Zeitraum der Daten eingrenzen können.Sinnigerweise muss die eingegebene Zahl zwischen 0 und den maximalen Tagen liegen.
Habe es schon mit if-Unterscheidungen usw probiert aber das klappt nicht.

Code: Alles auswählen

#Abfrage über maximalen Zeitraum
maxtage = len(datei_neu.index)

#Die Benutzereingabe wird auf überprüft
ungültigeeingabe = True
while ungültigeeingabe:

    try:
        a = int(input("Geben Sie den Beginn des Zeitraums ein (0 = 2020-03-02): "))
        b = int(input(f"Nun das Ende (max.{maxtage}):"))
        ungültigeeingabe = False
    except:
        print("Das ist keine gültige Zahl")
Olsen
User
Beiträge: 17
Registriert: Donnerstag 16. Oktober 2014, 17:46

meiner meinung müsste da etwas wie: if a > maxtage or a < 0
Benutzeravatar
__blackjack__
User
Beiträge: 13202
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Olsen: `ungültigeeingabe` ist überflüssig. Da macht man einfach eine ”Endlosschleife” (``while True:``) und bricht die mit ``break`` ab wenn man eine gültige Eingabe hat.

Keine ”nackten” ``except`` ohne konkrete Ausnahme(n) verwenden. Das behandelt *alle* Ausnahmen, auch die mit denen Du nicht rechnest und bei denen eine Ausgabe das wäre keine Zahl keinen Sinn macht. Zum Beispiel wenn der Benutzer versucht das Programm mit Strg+C abzubrechen, wenn man sich verschrieben hat und in dem ``try``-Block ein `NameError` auftritt, wenn aus irgendeinem Grund kein Arbeitsspeicher mehr zur Verfügung steht und ein `MemoryError` ausgelöst wird, und bei Sachen mit denen jetzt weder ich noch Du mit rechnen. Wenn man einen `ValueError` behandeln will, dann sollte man genau das tun: den `ValueError` behandeln, und nur den.

Was hat denn beim ``if`` nicht geklappt? Ich hätte die Bedingung wahrscheinlich anders ausgedrückt (``not 0 <= a <= maxtage``), aber das ist ja schon mal ein guter Anfang. `a` und `b` sind als Namen nicht so wirklich toll.

Diese Eingabe suggeriert IMHO, dass es für jeden Tag einen Eintrag gibt, also das es keine Lücken gibt. Ist das sichergestellt? Wird das im Programm nach dem einlesen überprüft. Benutzereingaben und Dateien — man glaubt manchmal gar nicht was für ”kreative” Sachen da manchmal dabei sind. 😉
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Olsen
User
Beiträge: 17
Registriert: Donnerstag 16. Oktober 2014, 17:46

Ich steh irgendwie auf dem Schlauch....ich weiß gerade nicht wie die Schleife bei gültiger Eingabe beendet wird.

Code: Alles auswählen

#Abfrage über maximalen Zeitraum
maxtage = len(datei_neu.index)

#Die Benutzereingabe wird auf überprüft
while True:
    try:
        anfang_zeitraum = int(input("Geben Sie den Beginn des Zeitraums ein (0 = 2020-03-02): "))
        if not 0 <= anfang_zeitraum <= maxtage:
            print("Unzulässige Zahl.")

        ende_zeitraum = int(input(f"Nun das Ende (max.{maxtage}):"))
        if not anfang_zeitraum <= ende_zeitraum <= maxtage:
            print("Unzulässige Zahl.")


    except ValueError:
        print("Bitte überprüfe deine Eingabe.")
        break
Sirius3
User
Beiträge: 17797
Registriert: Sonntag 21. Oktober 2012, 17:20

Das break ist zum Verlassen da, steht also an der falschen Stelle. Nach der Eingabe eines falschen Anfangswerts soll man trotzdem den Endwert eingeben? Entweder du trennst das in zwei while-Schleifen auf, oder du musst die if- Abfragen richtig verschachteln.
Warum ist das Anfangsdatum fix? Und warum muss man Zahlen statt eines Datums eingeben?
Olsen
User
Beiträge: 17
Registriert: Donnerstag 16. Oktober 2014, 17:46

Habe es nun über zwei while-Schleifen abgefangen. Klappt wunderbar und macht was es soll.

Das Anfangstdatum ist fix, da vor diesem Tag keine Daten erhoben worden sind. (die Datengrundlage wurde geändert)

Zahlen statt Datum, da mir das zunächst einfacher realisierbar schien. In einem weiteren Entwicklungsschritt werde ich die Eingabe über ein normales Datumsformat implementieren.
Antworten