SMHI har temperaturer och annan data från olika mätstationer i Sverige.
I detta uppdrag ska vi lära oss om listor och plottning i Python och använda detta för att undersöka temperaturdata från SMHI.
Denna uppgift är tänkt att köras i Python 3 på replit.com. Följ denna länk: https://replit.com/languages/python3 och klicka på create repl.
Vi börjar med några uppdrag för att se hur listor fungerar i Python.
En lista är en sekvens av värden. I koden nedan skapas en lista som sedan skrivs ut.
Uppdrag 1.1 a: Kopiera koden nedan och provkör den på replit.com.
temps = [14.1, 13.5, 17.5, 16.2, 18.9, 11.3]
print("Temperaturerna är:")
print(temps)
Några saker att observera:
- Man har hakparenteser runt listan
- Man har kommatecken mellan värdena i listan
- Decimaltal skrivs med punkt (inte med komma)
- Listan har sparats i variabeln
temps
- En
print
-sats gör att något skrivs ut
Värdena ovan är temperaturer som mätts upp under ett antal dagar i juni. Tabellen nedan visar temperaturerna, regnmängderna och vilka dagar det gäller.
dag | 3 | 7 | 10 | 11 | 14 | 17 |
---|---|---|---|---|---|---|
temp | 14.1 | 13.5 | 17.5 | 16.2 | 18.9 | 11.3 |
regn | 0 | 0.2 | 0.1 | 0.3 | 0 | 3.2 |
När vi programmerar i denna uppgift så kommer vi att skapa ytterligare två listor: days
och rain
, för att hålla reda på värdena i tabellen.
(Vi använder ofta engelska namn i programmen eftersom namn i program normalt inte får innehålla svenska tecken som å
, ä
och ö
.)
Uppdrag 1.1 b: Lägg till kod som skapar en lista days
med värdena för dagarna i tabellen (3, 7, 10, ...) och som sedan skriver ut listan, på liknande sätt som i förra exemplet. Provkör koden för att se att den fungerar.
Om du inte vet hur du skall göra så finns lösningen här.
Lösning
days = [3, 7, 10, 11, 14, 17]
print("Dagarna är:")
print(days)
Uppdrag 1.1 c: Lägg till kod som på liknande sätt skapar en lista rain
med värdena för regnmängderna i tabellen. Anropa också print
som tidigare så att du kan se att den nya listan har rätt värden.
Lösning
rain = [0, 0.2, 0.1, 0.3, 0, 3.2]
print("Regnmängderna är:")
print(rain)
I fortsättningen kommer vi att använda variablerna days
, temps
och rain
, så behåll koden som räknar ut dem. Print-satserna har vi bara haft för att kontrollera att rätt sak räknas ut, så de behövs inte längre. Du kan antingen ta bort dem, eller kommentera bort dem: I Python används brädgård (#
) för att ange att resten av raden är en kommentar. Till exempel:
print(temps) # Denna print-sats kommer att köras
# print(rain) Men denna är en kommentar och körs inte
Uppdrag 1.1 d: Kommentera bort några av print-satserna i din kod. (Kanske vill du dock ha kvar någon av print-satserna för att se att någonting händer när du kör programmet.)
Det finns en inbyggd funktion sum(list)
som kan summera elementen i en lista. Det finns också en inbyggd funktion len(list)
som ger längden på listan. ("len" står för "length".)
Uppdrag 1.2 a: Följande kod räknar ut summan av temperaturerna och längden på listan och skriver ut värdena. Kopiera och provkör koden. Vad blir resultatet?
s = sum(temps) # beräkna summa
print(s) # skriv ut
n = len(temps) # beräkna antalet
print(n) # skriv ut
Som du ser blir summan inte exakt 91.5, utan visas med många decimaler. Hur kan det vara så? Jo, det beror på att tal representeras binärt i datorn, dvs med nollor och ettor. Många decimaltal kan inte representeras exakt med binära tal, så omvandlingen ger avrundningsfel.
Uppdrag 1.2 b: För att få en finare utskrift kan vi använda funktionen round(v, d)
som avrundar ett värde v
till d
decimaler. Prova följande exempel:
third = 1/3 # beräkna värdet
rounded = round(third, 2) # avrunda
print(rounded) # skriv ut
Koden ovan kommer först att räkna ut 1/3, sedan avrunda till 2 decimaler (med round
) och sedan skriva ut resultatet (med print
).
Uppdrag 1.2 c: Om vi vill kan vi skriva allt som en enda sats i stället. Prova att ändra koden till följande sats. Vi har ersatt varje variabel med dess definition:
print(round(1/3, 2))
Vi kan observera att när en funktion anropas, så beräknas först argumenten till funktionen. Därför kommer först 1/3 att beräknas, sedan round
att anropas, och sist kommer print
att anropas (med resultatet från round
).
Uppdrag 1.2 d: Skriv liknande kod (med en eller flera rader, vilket du vill) så att summan av temperaturerna skrivs ut avrundat till en decimal.
Lösning:
Som en kodrad:
print(round(sum(temps),1))
Eller som flera rader:
s = sum(temps)
rounded = round(s, 1)
print(rounded)
Uppdrag 1.2 e: Nu när vi vet hur man räknar ut summan och längden av en lista så kan vi lätt räkna ut medeltemperaturen för värdena i temps
. Skriv kod som räknar ut medeltemperaturen och skriver ut resultatet, avrundat till en decimal.
Tips! Du kan skriva koden så att du gör varje sak i tur och ordning och sparar varje delresultat i en variabel:
- räkna ut summan av temperaturerna, spara i
s
- räkna ut antalet temperaturer (längden på listan), spara i
n
- räkna ut medelvärdet genom att dividera dessa, spara i
average_temp
- avrunda medelvärdet till en decimal, spara i
rounded
- skriv ut resultatet
Om du vill kan du sedan försöka skriva koden som en enda rad (byt ut varje användning av en variabel mot motsvarande beräkning).
Lösning
Som flera kodrader:
s = sum(temps)
n = len(temps)
average_temp = s/n
rounded = round(average_temp, 1)
print(rounded)
Eller som en enda rad:
print(round(sum(temps)/len(temps),1))
Observera att om man skriver allt på samma rad kan det ibland bli svårläst, även om koden blir kortare. Det kan vara bra att dela upp en stor beräkning i delar och sätta namn på de viktiga delarna. Då blir koden mer lättläst.
Uppdrag 1.2 f: Ändra din kod så att du använder två rader: en där du räknar ut medelvärdet av temperaturerna, och en där du avrundar och skriver ut. Något i följande stil:
average_temp = ...
print(round(..., ...))
Observera att man i Python ofta använder underscore (_
) inuti långa variabelnamn, som average_temp
, eftersom variabler inte får innehålla blanktecken. Det blir mer läsbart än om man skriver averagetemp
.
Lösning
average_temp = sum(temps)/len(temps)
print(round(average_temp, 1))
Uppdrag 1.2 g: Lägg till liknande kod för att räkna ut medelvärdet av regnmängderna.
Lösning
average_rain = sum(rain)/len(rain)
print(round(average_rain, 1))
Uppdrag 1.2 h: Snygga till ditt program så att du bara har kvar koden för att räkna ut days
, temps
, rain
, average_temp
och average_rain
. Övrig kod kan tas bort eller kommenteras bort.
Du kan accessa (komma åt) enskilda element i en lista lst
med notationen lst[i]
där i
är indexet (positionen) för elementet i listan. Första elementet har index 0, nästa index 1, osv.
(I programmering numreras element från 0 i stället för 1 för att det ofta ger enklare kod. Indexet är egentligen avståndet från det första elementet.)
Här är ett exempel på en lista där elementen är strängar.
song = ["glad", "såsom", "fågeln", "i", "morgonstunden"]
print(song[0], song[3], song[4])
Uppdrag 1.3 a: Kopiera och provkör koden ovan. Vilka element skrivs ut?
Observera att man kan skriva ut flera saker på samma rad genom att ha flera argument i samma print-sats.
Uppdrag 1.3 b: Vad händer om man försöker accessa "utanför" listan, med ett index som är för stort? Prova att göra t.ex. print(song[17])
. Du får ett felmeddelande med "Traceback" (talar om var felet uppstod) och "IndexError" (talar om vilken slags fel det var). Kan du förstå felmeddelandet?
Uppdrag 1.3 c: Skriv kod som skriver ut första, andra och tredje elementet i listan rain
.
Lösning
print(rain[0], rain[1], rain[2])
Uppdrag 1.3 d: Skriv kod som räknar ut medelvärdet av de tre första elementen i rain
.
Tips! Gör detta genom att lägga ihop de tre värdena och dividera med tre. Kalla detta värde t.ex. avg3
. Därefter avrundar du och skriver ut resultatet.
Blir värdet större eller mindre än medelvärdet för hela listan som du räknade ut tidigare?
Lösning
avg3 = (rain[0] + rain[1] + rain[2])/3
print(round(avg3, 1))
Uppdrag 1.4 a: En for
sats kan loopa över elementen i en lista. Provkör följande kod som skriver ut alla orden i listan song
:
for word in song:
print(word)
Saker att observera:
- For-loopen körs lika många varv som det finns element i listan.
- Variabeln
word
kallas loopvariabel. För varje varv fårword
nästa värde i listan. - Satsen
print(word)
skriver ut värdet.
Uppdrag 1.4 b: Du kan använda ett annat namn på loopvariabeln om du vill. Prova att ändra namnet från word
till w
och kör koden för att kontrollera att den gör samma sak som tidigare.
Uppdrag 1.4 c: Skriv kod som skriver en liknande loop, och som skriver ut alla regnmängderna i listan rain
. Här kan det passa att kalla loopvariabeln t.ex. r
.
Lösning
for r in rain:
print(r)
Uppdrag 1.4 d: För att loopa ett visst antal gånger används ofta en for
loop med en range
. Provkör följande exempel.
for i in range(4):
print("värdet är", i)
Observera att:
- Loopen gör 4 varv.
- Loopvariabeln
i
får värdena 0, 1, 2, 3 i tur och ordning
Uppdrag 1.4 e: Vi ska nu loopa på ett liknande sätt över rain
. För att veta hur många varv vi skall loopa använder vi len
. Provkör följande kod:
for i in range(len(rain)):
print(rain[i])
Det här verkar ju bara vara ett krångligare sätt att göra samma sak som vi gjorde i uppdraget 1.4 c. Men vi ska strax se att vi har mer nytta av loopvariabeln i
.
Uppdrag 1.4 f: Ändra koden så att även dagen och temperaturen skrivs ut i loopen. Till exempel ska de två första raderna bli:
3 14.1 0
7 13.5 0.2
Lösning
for i in range(len(rain)):
print(days[i], temps[i], rain[i])
Uppdrag 1.4 g: Ändra koden så att du lägger till begriplig text, t.ex. så att de första två raderna blir
Den 3 juni var temperaturen 14.1 grader och det regnade 0 mm.
Den 7 juni var temperaturen 13.5 grader och det regnade 0.2 mm.
Lösning
for i in range(len(rain)):
print("Den", days[i], "juni var temperaturen", temps[i], "grader och det regnade", rain[i], "mm.")
Uppdrag 1.4 h: I följande uppgifter behöver du ha kvar koden som räknar ut days
, temps
och rain
. Övrig kod kan tas bort eller kommenteras bort.
Nu skall vi titta på hur plottning fungerar i Python.
Vi börjar med att plotta en temperaturkurva med dagar på x-axeln och temperaturer på y-axeln.
Uppdrag 2.1a: Vi använder biblioteket matplotlib
för att plotta. Provkör följande kod:
import matplotlib.pyplot as plt
plt.ion() # Sätt på interactive mode
plt.plot(days, temps)
Några saker att observera:
import
-satsen ger oss access till biblioteketmatplotlib.pyplot
och låter oss använda det lite kortare namnetplt
för det.- anropet
plt.ion
står för "interactive mode on" och gör att plottar i fortsättningen visas automatiskt i ett fönster. - anropet till
plt.plot
-funktionen anger att vi vill hadays
på x-axeln ochtemps
på y-axeln.
Uppdrag 2.1b: Prova att spara plotten till en fil genom att lägga till följande kommando efter plot
-anropet:
plt.savefig("temperaturkurva.png")
Att observera:
plt.savefig()
sparar plotten som en bild som du kan hitta under Files på vänster sida av repl.it-fönstret. Klickar du på filen ser du samma bild som i automatiska plotten. Att spara till fil på detta sätt kan vara praktiskt speciellt om vi plottar olika bilder, eller om vi vill ladda ner bilden, t.ex. för att skriva ut den. Klicka påmain.py
för att se koden igen.
En viktig sak när man plottar är att listorna för x och y-värdena måste vara lika långa. Annars får man ett felmeddelande.
Till exempel är följande anrop felaktigt
plt.plot([3, 7, 10], temps)
eftersom listan av x-värden är kortare än temperaturlistan temps
.
Uppdrag 2.2:
- Provkör det felaktiga anropet ovan för att se att du får ett felmeddelande.
- Felmeddelandet innehåller mycket information, men längst ner hittar du en förklaring av felet (
ValueError: ...
). Kan du förstå förklaringen? - Kan du ändra koden så att du blir av med felmeddelandet? (Tips! Ändra listan med x-värden så att den har lika många element som
temps
.)
Lösning
I felmeddelandet kan man se att första listan har längden 3, medan den andra har längden 6. För att bli av med felmeddelandet kan man ändra första listan så att den också får 6 element. Till exempel:
plt.plot([3, 7, 10, 11, 14, 17], temps)
Det finns många olika möjligheter att göra plotten finare och mer informativ. Vi borde till exempel skriva ut
- vad x och y-axlarna visar (dag och grader Celsius)
- en teckenförklaring som säger vad kurvan visar (temperaturer i juni)
Det vore också bra att sätta en prick för varje mätvärde, eftersom många dagar saknar mätvärde. (T.ex. inleds mätvärden med värden från den 3:e och 7:e juni i exemplet.)
Uppdrag 2.3 a: Prova koden nedan för att se hur man får med denna information.
plt.plot(days, temps, "o-", label="temperaturer i juni")
plt.xlabel("dag")
plt.ylabel("grader Celsius")
plt.legend()
plt.savefig("temperaturkurva.png")
Förklaring:
- anropet
xlabel
skriver ut etikett (label) på x-axeln - anropet
ylabel
skriver ut etikett på y-axeln - anropet
legend
skriver ut en teckenförklaring ("legend" på engelska). - parametern
label=...
i plot-anropet sätter en etikett (label) på kurvan. Denna etikett skrivs ut om man anroparlegend
- parametern
o-
i plot-anropet ger ett "format" för kurvan, och säger att det skall vara en prick för varje mätvärde och linjer emellan. Det finns många andra "format" att välja på. T.ex. kommerr+--
att rita en röd kurva med ett plus-tecken för varje mätvärde och streckade linjer emellan.
Uppdrag 2.3 b: Kopiera koden för plottningen i föregående uppdrag och experimentera med andra värden för format, label, xlabel och ylabel. Kan du få en grön kurva med streckade linjer?
Om du är intresserad av fler exempel på vilka format som kan användas i plot-anrop kan du titta i den officiella handledningen för pyplot: https://matplotlib.org/tutorials/introductory/pyplot.html. Om du vill se alla möjligheter för format så hittar du det i dokumentationen för plot-funktionen: https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.plot.html, se sektionen Notes.
Format-parametern är ett exempel på en valfri parameter. Den har ett standardvärde som används om man inte anger parametern. Standardvärdet för format-parametern är b-
(blå linje).
Parametern label=...
är ett exempel på en namngiven parameter. Namngivna parametrar måste komma i slutet på anropet (efter icke-namngivna) och ordningen mellan dem spelar ingen roll. De är praktiska att använda när en funktion har väldigt många valfria parametrar (vilket plot
har).
Uppdrag 2.4: Nu kan du lite om plottning. Skriv kod för att plotta regnmängderna (använd listan rain
som vi skapade tidigare). Kan du göra plotten fin och informativ med etiketter på axlarna och en "legend" (så att man ser vilken kurva som är vilken)?
Tips! Arbeta i små steg: gör en sak i taget och provkör koden efter varje steg så du ser att det blir rätt.
- Anropa
plt.plot(...)
så att dagarna hamnar på x-axeln och regnmängderna på y-axeln. - Anropa
plt.savefig("regnkurva.png")
för att din plot ska sparas som en fil. - Om du har två anrop till
savefig
i ditt program bör du anropaplt.close()
efter den förstasavefig
, så att figuren rensas innan du börjar plotta nästa diagram. - Lägg till
o-
som parameter tillplot
för att få prickar för värdena. - Lägg till anrop till
plt.xlabel(...)
ochplt.ylabel(...)
för att sätta etiketter på axlarna. - Lägg till parametern
label=...
i plot-anropet och anrop tillplt.legend()
för att få ut "legenden" (teckenförklaringen) för kurvan.
Om du gjort rätt så bör ditt diagram se ut något i följande stil
Lösning
plt.plot(days, rain, "o-", label="regnmängder i juni")
plt.xlabel("dag")
plt.ylabel("mm")
plt.legend()
plt.savefig("regnkurva.png")
Vi kan lägga flera kurvor i samma diagram.
Uppdrag 2.5: Genom att göra flera anrop till plot
kan vi skapa ett diagram med flera kurvor. Ändra din kod så att du visar både regnmängden och temperaturen i samma diagram. Kan du göra ett fint informativt diagram med olika färg på kurvorna? Vad skall du skriva för etikett på y-axeln?
Lösning
Här är ett exempel på hur vi kan göra:
plt.plot(days, rain, "bo-", label="regnmängder i juni")
plt.plot(days, temps, "ro-", label="temperaturer i juni")
plt.xlabel("dag")
plt.ylabel("mm eller grader")
plt.legend()
plt.savefig("regnochtemp.png")
Vilka av dessa är en lista i python?
[0, 1, 7]
(0, 1, 7)
{0, 1, 7}
Svar
[0, 1, 7]
Vad skriver man för att få längden på en lista som kallas data
?
len(data)
size(data)
range(data)
Svar
len(data)
Vad skriver följande kodstycke ut?
list = [1, 3, 5]
print(sum(list))
Svar
9
Vad skriver följande kodstycke ut?
list = ["hej", "på", "dig"]
print(list[1])
Svar
på
Vilket fel får man när följande kod körs:
data = [1, 3, 5]
print(data[42])
IndexError: list index out of range
ValueError: x and y must have same first dimension ...
NameError: name 'data' is not defined
Svar
IndexError: list index out of range
Vad skriver följande kodstycke ut?
list = ["hej", "på", "dig"]
for word in list:
print(word)
Svar
hej
på
dig
Vad skriver följande kodstycke ut?
list = ["hej", "på", "dig"]
for i in range(2):
print(list[i])
Svar
hej
på
Vad behöver man skriva tidigare i koden för att kunna göra följande anrop: plt.plot(...)
?
import matplotlib
import matplotlib.pyplot
import matplotlib.pyplot as plt
Svar
import matplotlib.pyplot as plt
Vad kommer det att stå på x-axeln i plotten som genereras av följande kod?
x = [1, 2, 3]
y = [1, 4, 9]
plt.plot(x, y)
plt.xlabel("mina fina x-värden")
plt.ylabel("mina vackra y-värden")
Svar
mina fina x-värden
Vad behöver man skriva senare i koden för att diagrammet som skapas med plt.plot(...)
skall sparas i en fil med namnet file.png
?
plt.savefig("file.png")
plt.save()
plt.savefig(file.png)
Svar
plt.savefig("file.png")