Matplotlib IndexError: list index out of range

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Hypec
User
Beiträge: 183
Registriert: Mittwoch 1. August 2018, 16:11

Hallo,
ich habe das Problem bei meinem Code der Werte aus einer Csv Datei auslesen soll und als subplot darstellen soll, dass die beiden Zeilen 17 und 18 den Fehler IndexError: list index out of range im Debugger anzeigen, jedoch eigentlich bis auf den wert von "zeile" genau gleich wie zeile 16 aufgebaut sind. Kann mir jemand sagen woran das liegt?
Python

Code: Alles auswählen

import matplotlib.pyplot as plt

dateihandler = open('test.csv')

inhalt = dateihandler.read()

zeilen = inhalt.split('\n')

tabelle = []

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

time = [zeile[0] for zeile in tabelle]
luftfeuchtedrin = [zeile[1] for zeile in tabelle]
luftfeuchteausen = [zeile[3] for zeile in tabelle]

fig, ax = plt.subplots()
ax.plot(time, luftfeuchteausen, label="luftfeuchteausen")
ax.plot(time, luftfeuchtedrin, label="luftfeuchtedrin")
ax.legend()

plt.show()

pass
csv:

Code: Alles auswählen

2018-08-13 14:00:00,71.60,22.20,53.10,22.50,834,225.00
2018-08-13 15:00:00,60.40,23.40,54.20,23.40,830,230.00
2018-08-13 16:00:00,64.30,21.30,53.60,24.30,835,231.67
2018-08-13 17:00:00,62.50,26.90,59.50,26.90,829,742.75
2018-08-13 18:00:00,71.60,18.80,57.30,21.20,827,3643.33
2018-08-13 19:00:00,60.40,22.60,56.90,22.50,833,4084.17
2018-08-13 20:00:00,64.30,25.50,56.80,26.90,826,4517.17
2018-08-13 21:00:00,62.50,26.90,64.60,23.40,840,4342.92
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

Hat schon jemand erwähnt, dass Du das csv-Modul benutzen sollst? Ansonsten würde man über das Datei-Objekt direkt iterieren, statt die Datei komplett zu lesen, an den Zeileumbruchzeilen zu splitten und danach über den Index zu iterieren. Auch erst die komplette Zeile einer Liste hinzuzufügen und dann einen Teil davon in floats umzuwandeln, ist umständlich. Und die Zeile nach dem letzten Zeileumbruchzeichen scheint wohl leer zu sein. Ein einfach so rumstehendes `pass` ist unsinnig.

Code: Alles auswählen

import csv
import matplotlib.pyplot as plt

with open('test.csv') as lines:
    reader = csv.reader(lines, delimiter=',')
    tabelle = [
        row[:1] + [float(c) for c in row[1:]]
        for row in reader
    ] 

time = [zeile[0] for zeile in tabelle]
luftfeuchtedrin = [zeile[1] for zeile in tabelle]
luftfeuchteausen = [zeile[3] for zeile in tabelle]

fig, ax = plt.subplots()
ax.plot(time, luftfeuchteausen, label="luftfeuchteausen")
ax.plot(time, luftfeuchtedrin, label="luftfeuchtedrin")
ax.legend()
fig.show()
Benutzeravatar
__blackjack__
User
Beiträge: 13069
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Für Zeitreihen ist `pandas` auch immer ganz nett zu benutzen:

Code: Alles auswählen

from matplotlib import pyplot as plt
import pandas as pd


def main():
    data = pd.read_csv('test2.csv', header=None, index_col=0, parse_dates=True)
    data.index.name = 'Zeit'
    data[1].rename('Luftfeuchte aussen').plot(legend=True)
    data[3].rename('Luftfeuchte innen').plot(legend=True)
    plt.show()
    

if __name__ == '__main__':
    main()
Bild
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Hypec
User
Beiträge: 183
Registriert: Mittwoch 1. August 2018, 16:11

Vielen dank für die Antworten.
Hat schon jemand erwähnt, dass Du das csv-Modul benutzen sollst
Ich hab den ganzen oberen Teil mit einem Tutorial gemacht und der hat damit problemlos 4000 spalten aus einer csv Datei ausgewertet.
Benutzeravatar
__blackjack__
User
Beiträge: 13069
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Falls die ``for``-Schleife mit dem `range()` auch aus dem Tutorial stammt, dann taugt das nix. Egal was der Rechner schafft, das ist kein idiomatisches Python. Und das mit dem ``split('\n')`` macht Probleme wenn jede Zeile mit einem Zeilenende abgeschlossen ist, denn dann hat man am Ende der Liste einen leeren Eintrag. Das heisst selbst wenn man erst alles einliest, ist `split()` nicht die richtige Methode für den Job.

Und wenn man mit weniger Code und weniger Speicherverbrauch das gleiche erreichen kann, ist es IMHO sinnvoller das auch zu tun.

Dateien die man öffnet, sollte man auch wieder schliessen. Dazu eignet sich die ``with``-Anweisung, damit die Datei auch auf jeden Fall geschlossen wird, egal warum der ``with``-Block verlassen wird.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Hypec
User
Beiträge: 183
Registriert: Mittwoch 1. August 2018, 16:11

Ja du hast wahrscheinlich recht das es so wie in dem Tutorial gemacht wird sehr schlecht ist. Sirius kann man bei deinem plot noch Linien von der Uhrzeit hoch ziehen, da man so wenn das ganze 20 oder mehr Werte sind recht schwer zu erkennen wird welcher Wert zu welcher Uhrzeit gehört?
Benutzeravatar
__blackjack__
User
Beiträge: 13069
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Hypec: Man könnte da Linien hochziehen, üblicher wäre aber wohl das Gitter zu aktivieren oder ein Balkendiagramm zu erstellen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Hypec
User
Beiträge: 183
Registriert: Mittwoch 1. August 2018, 16:11

Wie kann ich das Gitter aktivieren?
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Indem du in die matplotlib Gallery schaust, dir dort einen Plot raussuchst, der dir gefaellt, und den dazugehoerigen Code anschaust um zu verstehen, was die da gemacht haben.
Benutzeravatar
__blackjack__
User
Beiträge: 13069
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Hypec: Schau Dir mal die Tutorials und Beispiele bei Matplotlib an und wenn Du ein Gitter siehst, schau wie's gemacht wird.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Hypec
User
Beiträge: 183
Registriert: Mittwoch 1. August 2018, 16:11

Oke danke werde ich machen
Hypec
User
Beiträge: 183
Registriert: Mittwoch 1. August 2018, 16:11

Ich habe es jetzt geschafft mit diesem code ein Gitter darzustellen. Wollte jetzt den plot als png anspeichern, was auch problemlos funktioniert bis auf das in dem Gitter die waagrechten Linien nicht mit auf dem Png angezeigt werden. Weiß jemand woran das liegt und wie ich das beheben kann?

Code: Alles auswählen

import csv
import matplotlib.pyplot as plt

with open('test.csv') as lines:
    reader = csv.reader(lines, delimiter=',')
    tabelle = [
        row[:1] + [float(c) for c in row[1:]]
        for row in reader
    ]

        
    
def luftfeuchte():
    
    time = [zeile[0] for zeile in tabelle]
    luftfeuchtedrin = [zeile[1] for zeile in tabelle]
    luftfeuchteausen = [zeile[3] for zeile in tabelle]

    fig, ax = plt.subplots()
    ax.plot(time, luftfeuchtedrin, label="luftfeuchtedrin")
    ax.plot(time, luftfeuchteausen, label="luftfeuchteausen")
    ax.grid(True)
    ax.legend()
    ax.set_title('Luftfeuchte')
    ax.set_ylabel('Luftfeuchtigkeit in %')
    ax.set_xlabel('Uhrzeit')

    fig.show()
Code Plot als Bild speichern:

Code: Alles auswählen

import csv
import matplotlib.pyplot as plt
from matplotlib.backends.backend_agg import FigureCanvasAgg
#from matplotlib.figure import Figure

with open('test.csv') as lines:
    reader = csv.reader(lines, delimiter=',')
    tabelle = [
        row[:1] + [float(c) for c in row[1:]]
        for row in reader
    ]

def luftfeuchte():

    time = [zeile[0] for zeile in tabelle]
    luftfeuchtedrin = [zeile[1] for zeile in tabelle]
    luftfeuchteausen = [zeile[3] for zeile in tabelle]
    
    fig, ax = plt.subplots()
    ax.plot(time, luftfeuchtedrin, label="luftfeuchtedrin")
    ax.plot(time, luftfeuchteausen, label="luftfeuchteausen")
    ax.grid(True)
    ax.legend()
    ax.set_title('Luftfeuchte')
    ax.set_ylabel('Luftfeuchtigkeit in %')
    ax.set_xlabel('Uhrzeit')

 
    FigureCanvasAgg(fig).print_png('luftfeuchte.png', dpi=50000)


luftfeuchte()
Benutzeravatar
__blackjack__
User
Beiträge: 13069
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Also bei mir funktioniert das nicht weil `time` keine Zahlen enthält (ValueError: invalid literal for float(): 2018-08-13 14:00:00).

Warum nicht `plt.savefig()`? Und die DPI-Angabe ist *viel* zu hoch. Da möchtest Du vieleicht lieber die Grösse der Abbildung grösser und dafür die DPI-Zahl kleiner wählen. Die DPI-Angabe kann in PNG gespeichert werden, und so etwas unrealistisch grosses macht dann bei der Weiterverarbeitung sicher irgendwo Probleme.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Hypec
User
Beiträge: 183
Registriert: Mittwoch 1. August 2018, 16:11

Was wäre eine angemessene dpi Zahl?
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Probier es doch aus. Was fuer DPI hat denn dein Monitor? Oder fang an, einfach mal 0en wegzulassen, bis du zB dein Ergebnis mit den gewuenschten waagerechten Linien bekommst. Du musst mal ein bisschen experimentierfreudiger werden, und Dinge ausprobieren und selbst loesen, statt wirklich bei jedem Schritt hier 3 Threads aufzumachen. Denn auf Dauer wird das nicht funktionieren.
Hypec
User
Beiträge: 183
Registriert: Mittwoch 1. August 2018, 16:11

Naja ich hab bevor ich das gefragt habe 5 , 150 ,5000 und 50000 also eigentlich aus jeder größenklasse was dabei
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ja und was war das Ergebnis? Kann ja keiner wissen hier. Und woher kennst du sonst so den Begriff DPI, und was hast du da so fuer Wertebereiche? Und was sagen die Dokumentation oder andere Quellen zur Methode print_png? Da findet man ja Beispiele, und kann sich daran langhangeln.
Hypec
User
Beiträge: 183
Registriert: Mittwoch 1. August 2018, 16:11

Das Ergebnis war bei allen gleich aber ich habe das Problem gerade eben gefunden es liegt nicht in der Bildverarbeitung sondern in Windows Fotos, mit Firefox und Fresh Paint werden die Linien angezeigt
Benutzeravatar
__blackjack__
User
Beiträge: 13069
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Hypec: Es liegt letztendlich an der aberwitzig hohen DPI-Zahl und dem damit verbundenen viel zu grossen Bild (in Pixeln), was Software dazu veranlasst es für die Anzeige verkleinern zu müssen. Und je nach dem mit welchem Algorithmus *das* gemacht wird, können Details die eigentlich da sind, halt sehr undeutlich werden oder ganz verschwinden. Die Frage ist da aber auch immer noch wieso Du so eine unrealistische DPI-Zahl angibst, die ja wirklich jenseits von jedem normalen Monitor oder Drucker liegt.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Hypec
User
Beiträge: 183
Registriert: Mittwoch 1. August 2018, 16:11

Wie gesagt ich habe es mit allen möglichen DPI-Zahlen ausprobiert und es hat mit keiner Funktioniert und selbst mit dem Code hier der die DPI auf einen Standardwert definiert ging es nicht.

Code: Alles auswählen

    plt.savefig('pictures/lux.png', dpi=None, transparent=True)
Antworten