6. Moment06 - Dataanalys

I detta moment ska vi arbeta med avancerade sätt att hantera data i Python. Vi fokuserar på kraftfulla tekniker som hjälper dig att hantera och analysera data på ett effektivt sätt. Dessa tekniker kommer inte bara att göra din kod kortare och tydligare, utan också hjälpa dig att lösa problem snabbare och enklare.

Info

Till detta moment finns en sida med lösningsförslag.

6.1 Avancerade listor och tupler

Nu ska vi fördjupa oss i hur man kan effektivisera och förbättra arbetet med listor och tupler i Python. Dessa tekniker ger dig möjlighet att göra mycket med lite kod, vilket minskar risken för fel och förbättrar läsbarheten.

6.1.1 List comprehension

List comprehensions gör det möjligt att skapa och filtrera listor mycket effektivt. En bra minnesregel när du använder list comprehension är:

[ uttryck for variabel in lista if villkor ]

Minnesregel:

  • Börja med vad du vill göra med varje element (uttrycket).
  • Ange därefter hur varje element hämtas från listan.
  • Lägg eventuellt till ett villkor för filtrering.

Kodexempel: List comprehension

# Vanlig loop för att skapa kvadrater
kvadrater = []
for x in range(1, 11):
    kvadrater.append(x2)

# Samma kod med list comprehension
kvadrater = [x2 for x in range(1, 11)]
# Lagrar [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# Filtrera fram jämna tal från en lista
jämna_tal = [x for x in range(20) if x % 2 == 0]
# Lagrar: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

Uppgift: m06u01

Skapa en lista med kuber av talen 1–20 med hjälp av list comprehension.

Uppgift: m06u02

Du har en lista med temperaturer: [18, 27, 22, 30, 15, 29]. Filtrera ut alla temperaturer över 25 grader.

6.1.2 Tupler och tuple-unpacking

Tupler är fasta grupperingar av data där antalet element inte förändras. De är särskilt användbara när du vet exakt hur många värden du kommer att hantera. Tuple-unpacking låter dig enkelt extrahera data ur en tuple, detta är smidigt att använda om man vill returnera flera värden ur en funktion.

Kodexempel: Tuple-unpacking med funktion

# Funktion som returnerar flera värden i en tuple
def koordinat():
    return (4, 7)

x, y = koordinat()
print(f"Koordinaten är ({x}, {y})")

Tuple-unpacking är naturligtvis användbart på andra ställen i koden och inte bara i funktioner.

Kodexempel: Tuple-unpacking

# Direkt tuple-unpacking
person = ("Olle", 16, "NA1")
namn, ålder, klass = person
print(f"{namn} är {ålder} år gammal och går i klass {klass}.")

Uppgift: m06u03

Skriv en funktion som returnerar högsta och lägsta temperaturen från listan [18, 27, 22, 30, 15, 29]. Använd tuple-unpacking för att skriva ut resultaten.

6.1.3 Använda map() och lambda

map() används för att applicera en funktion på varje element i en lista. Resultatet är ett nytt objekt som du enkelt kan konvertera tillbaka till en lista med list().

Generell struktur för map()

map(funktion, lista)
  • funktion är det som ska utföras på varje element (ofta en lambda-funktion).
  • lista är listan vars element du vill ändra eller bearbeta.

Kodexempel: Användning av map() och lambda

# Ursprunglig lista med temperaturer i Celsius
celsius = [0, 10, 20, 30]

# Omvandlar varje temperatur till Fahrenheit med hjälp av map och lambda
fahrenheit = list(map(lambda c: c * 9/5 + 32, celsius))

# Resultat
print(fahrenheit)  # Skriver ut: [32.0, 50.0, 68.0, 86.0]

Förklaring

  • Varje temperatur (c) multipliceras med 9/5 och därefter adderas 32.
  • Detta görs automatiskt på varje element i listan.
  • Resultatet samlas sedan upp i en ny lista. list() används för att typkonvertera ett map-objekt till en lista, eftersom ett map-objekt inte går att använda själv utan måste konverteras till något mer användbart, ofta en lista.

Vi kan också använda map() och lambda för att typkonvertera elementen i en lista.

Kodexempel: Användning av map() och lambda

# Ursprunglig lista med strängar
strängar = ['1', '2', '3', '4']

# Konverterar varje sträng till ett heltal
tal = list(map(lambda x: int(x), strängar))

# Resultat
print(tal)  # Skriver ut: [1, 2, 3, 4]

Förklaring

  • Varje element (x) i listan är från början en sträng.
  • int(x) används för att konvertera varje sträng till ett heltal.
  • Resultatet samlas i en ny lista.

Funktionen map()map är bra att kunna eftersom den hjälper dig att utföra samma operation på varje element i en lista utan att behöva skriva en loop varje gång. Detta gör din kod kortare, tydligare och lättare att läsa, och tillsammans med lambda-funktioner blir din kod ofta ännu mer kompakt och effektiv.

Uppgift: m06u04

Konvertera längder från meter till centimeter med hjälp av map() och lambda. Använd denna listan: [1.5, 3.2, 7.8].

Uppgift: m06u05

Omvandla listan med fysikkonstanter ['3.14', '9.81', '6.626', '1.602'] från strängar till flyttal.

6.1.4 Filtrering och sortering med lambda

Lambda-funktioner är praktiska när du snabbt vill skapa enkla funktioner för sortering eller filtrering utan att definiera separata funktioner. Tupler rekommenderas eftersom data vanligtvis är fasta och oföränderliga men det går också att göra med lista i lista.

Kodexempel: Exempel med tuple

elever = [("Anna", 85), ("Björn", 72), ("Cecilia", 95)]
sorterade_elever = sorted(elever, key=lambda elev: elev[1], reverse=True)

Kodexempel: Exempel med tuple

länder = [("Sverige", 10350000), ("Norge", 5400000), ("Island", 370000)]
stora_länder = [land for land in länder if land[1] >= 1000000]

Uppgift: m06u06

Sortera följande kommuner efter folkmängd: kommuner = [('Göteborg', 600000), ('Borås', 115000), ('Alingsås', 42000), ('Lerum', 45000), ('Partille', 40000), ('Mölndal', 70000), ('Kungsbacka', 87000)]

Uppgift: m06u07

Från listan ovan, filtrera ut kommuner med folkmängd mindre än 50 000 invånare.

Uppgift: m06u08

När du har filtrerat ut kommuner med folkmängd mindre än 50 000 invånare så sortera denna listan från flest till minst antal invånare.

6.2 Dictionaries och JSON-strukturer

I det här avsnittet bygger vi vidare på det du lärde dig i moment05 om dictionaries och JSON. Vi arbetar med mer komplexa datastrukturer och tittar på hur vi kan spara och läsa data på ett effektivt sätt.

En dictionary i Python är ett sätt att koppla ihop två saker: en nyckel och ett värde. Det gör det lätt att strukturera information som hör ihop – till exempel en persons namn och ålder eller ett föremåls namn och pris.

6.2.1 Repetition och fördjupning om dictionaries

Dictionaries i Python lagrar data i form av nyckel–värde-par. Du kan enkelt hämta, lägga till, uppdatera och ta bort information i en dictionary.

Kodexempel: En enkel dictionary

person = {
    "namn": "Alva",
    "program": "NA",
    "poäng": 2400
}

# Hämta ett värde
print(person["namn"])

# Lägg till en ny nyckel
person["klass"] = "NA22"

# Uppdatera ett värde
person["poäng"] += 100

# Iterera över dictionaryn
for nyckel, värde in person.items():
    print(f"{nyckel}: {värde}")

Utskrift

Alva
namn: Alva
program: NA
poäng: 2500
klass: NA22

Här skapas en dictionary med information om en elev. Vi visar hur man hämtar ett värde, lägger till en ny nyckel, uppdaterar ett befintligt värde och loopar över alla nycklar och värden i dictionaryn.

Lägg märke till att du kan använda person["namn"] för att hämta ett specifikt värde – precis som med listor, fast med namn istället för siffra.

Uppgift: m06u09

Skapa en dictionary för en elev med följande information:

  • namn
  • ålder
  • program
  • intressen (lista)

Skriv ut alla nyckel–värde-par med en loop.

6.2.2 JSON-strukturer

JSON (JavaScript Object Notation) är ett standardformat för att spara data – till exempel när du skickar information mellan olika program eller sparar information mellan körningar. I Python kan du enkelt omvandla dictionaries till JSON och tvärtom.

Det här är särskilt användbart när du vill lagra strukturerad data i en fil och senare kunna läsa in och analysera den.

Kodexempel: Konvertera dictionary till JSON-sträng

import json

person = {"namn": "Alva", "program": "NA", "poäng": 2400}
json_str = json.dumps(person, indent=2, ensure_ascii=False)
print(json_str)

Funktionen json.dumps() omvandlar en dictionary till en JSON-sträng. Parametern indent=2 gör att resultatet blir lättläst.

Om du vill att svenska tecken som å, ä och ö ska synas korrekt, kan du lägga till ensure_ascii=False.

Utskrift

{
  "namn": "Alva",
  "program": "NA",
  "poäng": 2400
}

Kodexempel: Spara och läsa från JSON-fil

import json

person = {"namn": "Alva", "program": "NA", "poäng": 2400}

# Spara till fil
with open("elev.json", "w", encoding='utf-8') as fil:
    # ensure_ascii = False innebär att å/ä/ö sparas korrekt.
    json.dump(person, fil, indent=2, ensure_ascii=False)

# Läsa från fil
with open("elev.json", encoding='utf-8') as fil:
    data = json.load(fil)
    print(data)
    print(data["namn"])

Utskrift

{'namn': 'Alva', 'program': 'NA', 'poäng': 2400}
Alva

elev.json

{
  "namn": "Alva",
  "program": "NA",
  "poäng": 2400
}

Uppgift: m06u10

Skapa en dictionary för en bok med titel, författare och antal sidor. Spara den som en JSON-fil och läs sedan in den igen och skriv ut titel och antal sidor.

6.2.3 Komplexa datastrukturer

I mer avancerade program behöver man ofta kombinera listor och dictionaries. Ett vanligt exempel är att ha en lista av dictionaries, t.ex. en lista med elever eller mätdata.

Kodexempel: Lista med dictionarys

elever = [
    {"namn": "Alva", "program": "NA"},
    {"namn": "Elias", "program": "TE"},
    {"namn": "Sara", "program": "NA"}
]

for elev in elever:
    print(f"{elev['namn']} går {elev['program']}")

Nu har vi tagit steget vidare från enstaka dictionaries till en lista av dictionaries. Den här strukturen är vanlig när man vill hantera flera enheter av samma typ – t.ex. en lista av elever eller produkter i en butik.

Varje element i listan är en dictionary med samma uppsättning nycklar, vilket gör det lätt att loopa igenom och analysera datan.

Utskrift

Alva går NA
Elias går TE
Sara går NA

6.2.3.1 Sidospår: Shorthanded if (ternär operation)

När du vill tilldela en variabel ett värde baserat på ett enkelt villkor kan du använda en kompakt form som kallas shorthand if eller mer formellt: ternär operator.

Kodexempel: Shorthanded if

film = {"titel": "Inception", "tillåten_ålder": 15, "textad": True}
textstatus = "har undertext" if film["textad"] else "har ingen undertext"
print(f"{film['titel']} är tillåten från {film['tillåten_ålder']} år och {textstatus}.")

Det är exakt samma sak som att skriva:

Kodexempel: Vanlig if-sats

if film["textad"]:
    textstatus = "har undertext"
else:
    textstatus = "har ingen undertext"

print(f"{film['titel']} är tillåten från {film['tillåten_ålder']} år och {textstatus}.")

Detta är ett smidigt sätt att skriva kortare kod, men båda varianterna fungerar lika bra. Du kan själv välja vad som känns mest läsbart.

Uppgift: m06u11

Skapa en lista med, minst tre, kurser du läser på skolan som var och en representeras som en dictionary. I denna dictionaryn sparar du namnet på läraren och om det finns en lärobok eller inte i kursen.
Skriv ut en snygg lista med all information.

6.2.4 Nästlade strukturer

I vissa situationer räcker det inte med en enkel dictionary eller en lista av dictionaries. Då kan vi kombinera dem på ännu mer avancerade sätt, t.ex. med listor inuti dictionaries eller dictionaries inuti listor som i sin tur innehåller fler listor. Det här är användbart om du vill organisera till exempel skolklasser med flera elever och varje elev har flera betyg.

Kodexempel: Lista med klasser, där varje klass innehåller en lista med elever

klasser = [
    {
        "klass": "NA22",
        "elever": [
            {"namn": "Alva", "ålder": 17},
            {"namn": "Joel", "ålder": 18}
        ]
    },
    {
        "klass": "TE22",
        "elever": [
            {"namn": "Sara", "ålder": 17},
            {"namn": "Omar", "ålder": 18}
        ]
    }
]

# Skriv ut alla elever och vilken klass de går i
for klass in klasser:
    for elev in klass["elever"]:
        print(f"{elev['namn']} går i {klass['klass']}")

Utskrift

Alva går i NA22
Joel går i NA22
Sara går i TE22
Omar går i TE22

Kodexempel: En elev med en lista av provresultat

elev = {
    "namn": "Alva",
    "program": "NA",
    "provresultat": [78, 84, 92]
}

# Räkna ut medelvärde
medel = sum(elev["provresultat"]) / len(elev["provresultat"])
print(f"{elev['namn']} har ett medelvärde på {medel:.1f}")

Utskrift

Alva har ett medelvärde på 84.7

Uppgift: m06u12

Skapa en dictionary för en elev med följande information:

  • namn
  • ålder
  • program
  • intressen (lista)

Skapa en struktur som innehåller två klasser. Varje klass ska innehålla minst två elever.
Varje elev ska vara en dictionary med namn, ålder och en lista av betygpoäng (0, 10, 12.5, 15, 17.5 eller 20).

Skriv ut namnet på varje elev, vilken klass hen går i och elevens betygsmedelvärde.

Nu har du testat på olika sätt att strukturera och organisera data i Python. Genom att kombinera listor och dictionaries kan du bygga egna små databaser – helt i kod.

I nästa avsnitt kommer vi att använda dessa strukturer för att göra enklare analyser, t.ex. räkna ut medelvärden, filtrera data och plocka ut det viktigaste.

Uppgift: Projektuppgift, del 1

Under resten av momentet så kommer en liten större uppgift byggas upp steg för steg. Detta är första delen av den uppgiften.

Uppgiften är att bygga upp en struktur för ett klimatdatasystem. Du får data från olika orter: platsnamn, medeltemperatur, nederbörd och datum.

  • Strukturera varje mätning som en dictionary
  • Samla alla mätningar i en lista
  • Spara hela listan som JSON
  • Läs in datan från filen och skriv ut en enkel lista med all information. Om du kan så sortera utskriften efter nederbörd i fallande skala. Mest för att bevisa att det i Borås regnar mest.

Du kan bygga vidare på denna uppgift efter varje delmoment eller göra allt i slutet.

6.3 Enkel dataanalys utan bibliotek

I detta avsnitt fokuserar vi på att analysera och bearbeta data med hjälp av ren Python, utan att använda några externa bibliotek som t.ex. pandas eller numpy. Du kommer att lära dig att samla, filtrera, räkna och sammanställa information från listor och dictionaries på ett effektivt sätt.

Det är viktigt att kunna utföra dessa analyser med grunderna i Python innan man lägger till fler verktyg. För dig som senare vill fördjupa dig i dataanalys finns det flera kraftfulla bibliotek att utforska, som t.ex. pandas för datahantering, numpy för avancerad numerisk beräkning och matplotlib för diagram och visualisering. Men i detta moment håller vi oss till det vi kan bygga själva från grunden.

6.3.1 Grundläggande analys (summa, medel, max/min)

I det här avsnittet använder vi inbyggda Python-funktioner för att analysera data: sum(), len(), max() och min(). Vi räknar ut t.ex. medelvärde, högsta poäng eller antal.

Kodexempel: Enkel lista

resultat = [72, 88, 91, 65, 78]

print("Antal resultat:", len(resultat))
print("Högsta poäng:", max(resultat))
print("Lägsta poäng:", min(resultat))
print("Medelpoäng:", sum(resultat)/len(resultat))

Utskrift

Antal resultat: 5
Högsta poäng: 91
Lägsta poäng: 65
Medelpoäng: 78.8

Kodexempel: Lista med dictionaries

elever = [
    {"namn": "Alva", "resultat": [65, 72, 88]},
    {"namn": "Elias", "resultat": [78, 91]},
    {"namn": "Sara", "resultat": [84]}
]

alla_resultat = []
for elev in elever:
    alla_resultat += elev["resultat"]

print("Totalt antal resultat:", len(alla_resultat))
print("Högsta poäng:", max(alla_resultat))
print("Lägsta poäng:", min(alla_resultat))
print("Medelpoäng:", round(sum(alla_resultat)/len(alla_resultat), 2))

Utskrift

Totalt antal resultat: 6
Högsta poäng: 91
Lägsta poäng: 65
Medelpoäng: 79.67

Uppgift: m06u13

Du har en lista med elever och deras resultat:

Lista med elever och resultat

elever = [
  {"namn": "Anna", "poäng": [5, 7, 6]},
  {"namn": "Nils", "poäng": [8, 6]},
  {"namn": "Lea", "poäng": [9]}
]
  • Skapa en gemensam lista med alla poäng
  • Räkna ut totalt antal, medel, max och min

6.3.2 Filtrera och analysera delar av data

Vi vill ofta analysera en delmängd av datan, t.ex. bara värden som är över ett visst gränsvärde. Här visar vi först hur du kan filtrera en enkel lista, och därefter hur du kan jobba med mer komplex data där varje objekt innehåller en egen lista av värden.

Kodexempel: Filtrera i lista

poäng = [4, 8, 6, 10, 3]
filtrerade = [p for p in poäng if p > 5]
print("Poäng över 5:", filtrerade)

Utskrift

Poäng över 5: [8, 6, 10]

Inom mer avancerade datamodeller har vi ofta listor med dictionaries där en nyckel pekar på en lista av värden. Då behöver vi iterera både över objekten och över listorna i varje objekt.

Kodexempel: Filtrera i lista av dictionaries (med lista som värde)

def filtrera_höga(elev):
    return [v for v in elev["resultat"] if v >= 7]

elever = [
  {"namn": "Anna", "resultat": [5, 7, 6]},
  {"namn": "Nils", "resultat": [4, 3]},
  {"namn": "Lea", "resultat": [9, 10]}
]

for elev in elever:
    print(elev["namn"], ":", filtrera_höga(elev))

Utskrift

Anna : [7]
Nils : []
Lea : [9, 10]

Det är ofta en fördel att ha en funktion för att kunna tillämpa filtret på ny data senare, istället för att lagra resultatet som ny nyckel.

Uppgift: m06u14

Du har en lista med elever och deras resultat:

Kodexempel:

elever = [
  {"namn": "Ida", "poäng": [3, 7, 8]},
  {"namn": "Leo", "poäng": [5, 4]},
  {"namn": "Zara", "poäng": [9, 6]}
]
  • Skriv en funktion som filtrerar ut alla poäng mellan 5 och 8. 5 och 8 skall finnas kvar efter filtreringen.
  • Använd funktionen på varje elev

6.3.3 Gruppering och räknare

Om vi har data med kategorier (t.ex. elevernas program eller ämnesval) kan vi gruppera dem och räkna hur många som tillhör varje grupp. Det finns flera sätt att bygga upp en sådan summering.

När man bygger upp en räknare i en dictionary behöver man kontrollera om nyckeln redan finns. Det kan göras på två sätt:

  • Med if/else: Kontrollera om nyckeln finns innan man ökar värdet.
  • Med .get(): Hämtar värdet om det finns, annars returneras ett standardvärde (t.ex. 0).

.get() är ett smidigt sätt att undvika KeyError när man bygger upp en ny dictionary steg för steg.

Kodexempel: Gruppering och räknare, två metoder

elever = [
    {"namn": "Alva", "favoritämnen": ["Kemi", "Biologi"]},
    {"namn": "Elias", "favoritämnen": ["Fysik"]},
    {"namn": "Sara", "favoritämnen": ["Kemi"]},
    {"namn": "Lina", "favoritämnen": ["Biologi", "Kemi"]}
]

# Variant 1: med if/else
antal1 = {}
for elev in elever:
    for ämne in elev["favoritämnen"]:
        if ämne in antal1:
            antal1[ämne] += 1
        else:
            antal1[ämne] = 1

# Variant 2: med .get()
antal2 = {}
for elev in elever:
    for ämne in elev["favoritämnen"]:
        antal2[ämne] = antal2.get(ämne, 0) + 1  # .get() returnerar 0 om nyckeln saknas

print("Med if/else:", antal1)
print("Med get():", antal2)

Utskrift

Med if/else: {'Kemi': 3, 'Biologi': 2, 'Fysik': 1}
Med get(): {'Kemi': 3, 'Biologi': 2, 'Fysik': 1}

Båda metoder ger samma resultat, men .get() kan vara lite smidigare att skriva.

En sådan sammanställning passar utmärkt för att senare visualisera med matplotlib.

Uppgift: m06u15

Du har en lista med personer och deras språk de talar:

Lista med talade språk

personer = [
  {"namn": "A", "språk": ["svenska", "engelska"]},
  {"namn": "B", "språk": ["engelska"]},
  {"namn": "C", "språk": ["svenska", "tyska"]},
  {"namn": "D", "språk": ["engelska", "tyska"]}
]

Skapa en dictionary med antal personer som talar varje språk. Sortera gärna utskriften med de mest talade språken först.

Använd gärna både if/else och .get() och jämför

Uppgift: Projektuppgift, del 2

I denna del ska du fortsätta arbeta med den datafil som du jobbade med i del 1. Målet är att bearbeta datan till ett format som passar för att skapa diagram i nästa moment.

Här kommer en lämplig struktur på json-filen som enkelt kan läsas in som en dictionary i python och sedan arbetas vidare med.

klimatdata.json

[
  {"plats": "Göteborg", "temp": 13.6, "nederbörd": 4.1, "datum": "2024-09-01"},
  {"plats": "Borås", "temp": 17.8, "nederbörd": 2.9, "datum": "2024-09-01"},
  {"plats": "Alingsås", "temp": 22.9, "nederbörd": 1.0, "datum": "2024-09-01"}
  // ... fler rader enligt tidigare struktur
]

Uppgiften i denna del är att sammanställa data och förbereda för att i nästa del skapa utskrifter av bearbetat data och även rita upp diagram.

  • Läs in json-filen eller se till att din datastruktur är lik filens struktur.
  • Gruppera temperaturen per plats och räkna ut medeltemperatur per plats.
  • Gör samma sak för nederbörd – d.v.s. beräkna medelnederbörd per plats.
  • Spara de färdiga resultaten i två dictionaries:
    • medel_temp = {"Göteborg": 17.1, "Borås": 19.2, ...}
    • medel_nederbörd = {"Göteborg": 3.5, "Borås": 5.2, ...}

Du kan bygga vidare på denna uppgift efter varje delmoment eller göra allt i slutet.

6.4 Visualisering med matplotlib

I detta avsnitt lär du dig att skapa enkla diagram i Python med hjälp av matplotlib.pyplot. Vi använder inga externa dataverktyg som pandas – endast grundläggande Python och listor/dictionaries.

Du får lära dig att skapa tre vanliga typer av diagram:

  • Stapeldiagram – för att visa jämförelser mellan kategorier
  • Linjediagram – för att visa förändring över tid
  • Cirkeldiagram – för att visa fördelningar

Vi går också igenom hur du kan formatera diagrammen på olika sätt.

6.4.1 Stapeldiagram – jämförelser mellan grupper

För att kunna använda matplotlib.pyplot måste du först installera paketet matplotlib. Det gör du på ett av följande sätt:

  • I Windows: skriv pip install matplotlib i terminalen (kommandoprompt eller i PyCharm)
  • På Mac: använd pip3 install matplotlib eller lägg till via "Python Packages" i PyCharm

När du installerat klart kan du importera biblioteket och börja rita diagram. Antag att vi har data om hur många elever som valt olika språk:

Kodexempel: Enkelt stapeldiagram

import matplotlib.pyplot as plt  # Importerar ritverktyget pyplot från matplotlib

språk = ["Franska", "Spanska", "Tyska"]
antal = [12, 18, 7]
plt.bar(språk, antal)            # Skapar ett stapeldiagram där x = språk (etiketter), y = antal (höjd på staplar)
plt.title("Val av språk")        # Lägger till en rubrik
plt.xlabel("Språk")              # Etikett under x-axeln
plt.ylabel("Antal elever")       # Etikett vid y-axeln
plt.show()                       # Visar diagrammet i ett nytt fönster

Diagram

Diagram

Det här diagrammet visar ett enkelt stapeldiagram där varje stapel representerar antalet elever per språkval.

Meddelanden vid körning på Mac

När du kör Python-program på Mac, särskilt sådana som ritar diagram eller öppnar grafiska fönster (t.ex. med matplotlib), kan det hända att du ser meddelanden som dessa i terminalen:

Kodexempel:

2025-04-28 10:56:08.346 Python[4043:7849391] +[IMKClient subclass]: chose IMKClient_Modern
2025-04-28 10:56:08.346 Python[4043:7849391] +[IMKInputSession subclass]: chose IMKInputSession_Modern

Detta är helt normalt och betyder att macOS väljer en modern hantering av tangentbordsinmatning (IMK står för Input Method Kit) för det grafiska fönstret som öppnas. Det påverkar inte ditt program på något sätt och kan ignoreras.

6.4.1.1 Anpassning av stapeldiagram

Nu när vi vet hur man bygger grundläggande stapeldiagram kan vi också förfina dem med färger, etiketter och tydligare staplar.

Kodexempel:

plt.bar(språk, antal, color=["red", "green", "blue"])  # Välj färger för varje stapel
plt.yticks(range(0, 21, 5))  # Visa bara hela femtal på y-axeln

Diagram

Diagram

Vill du ha liggande staplar istället för stående, använd barh() i stället för bar():

Kodexempel:

plt.barh(språk, antal, color=["red", "green", "blue"])  # Välj färger för varje stapel
plt.xticks(range(0, 21, 5))  # Visa bara hela femtal på x-axeln

Diagram

Diagram

Det går också att visa exakta värden på varje stapel.

Kodexempel:

for i in range(len(språk)):
    plt.text(språk[i], antal[i] + 0.5, str(antal[i]), ha="center")  # Text ovanför varje stapel

Diagram

Diagram

Justera bredd och kantlinjer går också

Kodexempel:

plt.bar(språk, antal, color="green", width=0.6, edgecolor="black")  # Smalare staplar med grön färg och svart kant

Diagram

Diagram

Uppgift: m06u17

Skapa ett stapeldiagram som visar befolkningen i fem kommuner:

  • Skapa ett stående stapeldiagram
  • Använd olika färger för staplarna
  • Rotera x-etiketterna 30 grader
  • Visa värden ovanför varje stapel
  • Lägg till titel och axelrubriker

Tips: Funktionen plt.xticks(rotation=45) används för att rotera etiketterna på x-axeln så att de inte krockar eller blir svårlästa.

Data

kommuner = ["Göteborg", "Borås", "Alingsås", "Lerum", "Kungsbacka"]
befolkning = [587000, 113000, 43000, 43000, 85000]

Stapeldiagram passar bra för jämförelser mellan kategorier. Men om vi istället vill visa utveckling över tid är linjediagram ett bättre val.

6.4.2 Linjediagram

Här visar vi hur antalet elever som valt programmering har förändrats över fyra läsår.

Kodexempel: Linjediagram

import matplotlib.pyplot as plt
år = ["2020", "2021", "2022", "2023"]      # Värden för x-axeln (tidslinje)
antal = [14, 18, 21, 25]                   # Värden för y-axeln (antal elever)
plt.plot(år, antal, marker="o")            # Skapar ett linjediagram med markeringar vid varje punkt
plt.title("Elever som valt Programmering") # Rubrik för diagrammet
plt.xlabel("År")                           # Etikett under x-axeln
plt.ylabel("Antal elever")
plt.grid(True)                             # Visar både horisontella och vertikala hjälplinjer
plt.show()

Vill du bara visa linjer på en axel?

Kodexempel:

plt.grid(axis="y")  # Endast horisontella linjer
plt.grid(axis="x")  # Endast vertikala linjer

Detta kan ge ett renare utseende i vissa diagram.

Diagram

Diagram

Linjediagram passar bra när du vill visa trender eller utveckling över tid.

6.4.2.1 Färg och linjestil

Kodexempel:

plt.plot(år, antal, color="green", linestyle="--", marker="o")  # Streckad grön linje med cirkelmarkörer

Diagram

Diagram

6.4.2.2 Flera linjer i samma diagram

Kodexempel:

år = ["2020", "2021", "2022", "2023"]
prog = [14, 18, 21, 25]
webb = [10, 15, 17, 22]

plt.plot(år, prog, label="Programmering", color="blue", marker="o")
plt.plot(år, webb, label="Webbutveckling", color="orange", marker="s")
plt.legend()  # Visa etikettförklaring

Diagram

Diagram

6.4.2.3 Visa exakta värden vid varje punkt

Kodexempel:

for i in range(len(år)):
    plt.text(år[i], antal[i] + 0.5, str(antal[i]), ha="center")

Diagram

Diagram

Dessa små förbättringar kan göra linjediagrammet både snyggare och lättare att tolka.

Uppgift: m06u18

Skapa ett linjediagram som visar hur många elever som deltagit i skolans teknikklubb under de senaste fem åren:

Kodexempel:

år = ["2019", "2020", "2021", "2022", "2023"]
deltagare = [8, 12, 10, 15, 18]

Uppgiften är att du skall:

  • Rita ett linjediagram där punkterna markeras med cirklar
  • Lägg till titel och axelrubriker
  • Använd valfri färg på linjen
  • Visa varje värde ovanför respektive punkt
  • Aktivera rutnät (grid)

6.4.3 Cirkeldiagram

Om du vill visa andelar av en helhet passar ett cirkeldiagram bra:

Kodexempel:

import matplotlib.pyplot as plt
ämnen = ["Biologi", "Kemi", "Fysik"]               # Etiketter för varje tårtbit
andelar = [25, 30, 45]                             # Storlek (andel) för varje kategori
plt.pie(andelar, labels=ämnen, autopct="%1.0f%%")  # Skapar cirkeldiagram med etiketter och procent
plt.title("Fördelning av favoritämnen")            # Rubrik för cirkeldiagrammet
plt.show()

Diagram

Diagram

Varje sektor visar andelen elever som valt respektive ämne.

Tänk på att cirkeldiagram fungerar bäst med några få tydliga kategorier. Om du har många värden eller stora skillnader kan staplar vara tydligare.

6.4.4 Kombinerade diagram – staplar och linjer i samma figur

Ibland kan vi vilja visa flera datatyper samtidigt, t.ex. jämföra aktuella värden och en trend. Då kan vi kombinera flera diagramformer i samma bild.

6.4.4.1 Grupperade staplar – flera serier i samma diagram

När du vill visa flera jämförelsepunkter för varje kategori, t.ex. antal elever i olika kurser över tre år, kan du använda grupperade staplar:

Kodexempel:

kurser = ["Programmering", "Webbutveckling", "Matematik"]  # Lista med kurser
år_2021 = [15, 10, 20]  # Antal elever år 2021
år_2022 = [17, 13, 19]  # Antal elever år 2022
år_2023 = [20, 15, 22]  # Antal elever år 2023

x_pos = list(range(len(kurser)))  # Skapar en lista med positioner 0, 1, 2 för kurserna
bredd = 0.25  # Bredd på varje stapel

# Justera positioner för staplarna så att de hamnar bredvid varandra
x1 = [x - bredd for x in x_pos]  # Flytta första stapeln åt vänster
x2 = x_pos                       # Andra stapeln i mitten
x3 = [x + bredd for x in x_pos]  # Flytta tredje stapeln åt höger

# Rita staplar för varje år
plt.bar(x1, år_2021, width=bredd, label="2021")
plt.bar(x2, år_2022, width=bredd, label="2022")
plt.bar(x3, år_2023, width=bredd, label="2023")

# Lägg till etiketter och titel
plt.xticks(x_pos, kurser)
plt.xlabel("Kurs")
plt.ylabel("Antal elever")
plt.title("Antal elever per kurs och år")
plt.legend()
plt.tight_layout()
plt.show()

Diagram

Diagram

Det här ger ett tydligt diagram där du kan jämföra flera år sida vid sida för varje kurs.

Förutom att visa flera stapelgrupper kan du även kombinera olika typer av diagram i en och samma figur. Det är särskilt användbart om du vill visa både aktuella värden och en jämförelse eller trend på samma gång. Här är ett exempel där vi visar antalet elever i två ämnen: ett med stapeldiagram och ett med linjediagram.

Kodexempel:

import matplotlib.pyplot as plt

ämnen = ["Fysik", "Kemi", "Biologi", "Teknik"]
antal = [12, 15, 9, 11]
utveckling = [10, 13, 8, 12]  # För att visa en trend med linje

plt.bar(ämnen, antal, label="Nuvarande")
plt.plot(ämnen, utveckling, color="red", marker="o", label="Utveckling")

plt.title("Elever per ämne och utveckling")
plt.xlabel("Ämne")
plt.ylabel("Antal elever")
plt.legend()
plt.show()

Diagram

Diagram

Detta kan vara användbart när du vill visa både aktuella värden och en jämförelse eller trend i samma bild.

6.4.4.2 Kombinerat med två y-axlar

Om dina dataserier har olika enheter eller skala – t.ex. poäng och tid – kan du använda två y-axlar:

Kodexempel:

import matplotlib.pyplot as plt  # Importera ritverktyget

ämnen = ["Fysik", "Kemi", "Biologi", "Teknik"]  # Lista med ämnen
betyg = [3.1, 3.5, 3.2, 3.0]  # Lista med medelbetyg (skalor t.ex. 1-5)
antal = [20, 25, 18, 22]  # Lista med antal elever

fig, ax1 = plt.subplots()  # Skapa en figur och en första axel (ax1)

# Stapeldiagram på första y-axeln
ax1.bar(ämnen, antal, color="lightblue", label="Antal elever")
ax1.set_ylabel("Antal elever", color="lightblue")  # Etikett till vänster (y-axel 1)
ax1.tick_params(axis="y", labelcolor="lightblue")  # Färgsätt y-etiketter så de matchar staplarna

# Skapa en andra y-axel som delar x-axeln
ax2 = ax1.twinx()

# Linjediagram på andra y-axeln
ax2.plot(ämnen, betyg, color="darkgreen", marker="o", label="Medelbetyg")
ax2.set_ylabel("Medelbetyg", color="darkgreen")  # Etikett till höger (y-axel 2)
ax2.tick_params(axis="y", labelcolor="darkgreen")  # Färgsätt y-etiketter så de matchar linjen

# Lägg till en titel och fixa layout
plt.title("Antal elever och medelbetyg per ämne")
fig.tight_layout()  # Justera layout så allt får plats
plt.show()

Diagram

Diagram

Detta gör det enkelt att läsa av både värden och trender – även om de tillhör olika skalor.

Här kommer några praktiska förbättringar du kan göra:

Kodexempel:

plt.xticks(rotation=20)  # Rotera etiketter om de krockar
plt.tight_layout()       # Justera automatiskt layout
plt.savefig("diagram.png")  # Spara till bildfil

Svenska tecken fungerar ofta bra, men om de ser konstiga ut kan du testa att spara filen som UTF-8 encodings='utf-8' och använda ett typsnitt som stödjer ÅÄÖ.

6.4.4.3 Styra skalan på y-axlarna

Om du vill sätta egen gräns för y-axeln – till exempel om du vill tvinga staplarna att börja på 0 och sluta på 10 – kan du använda följande metoder

Kodexempel:

ax1.set_ylim(0, 10)  # För stapeldiagrammets axel
ax2.set_ylim(-5, 25) # För linjediagrammets axel

Detta används när du skapat egna axlar (som ax1, ax2) och vill styra varje y-axel exakt. Om du endast använder en y-axel och inte har skapat den tidigare så kan du istället skriva följande kod:

Kodexempel:

plt.ylim(0, 10)

Om du vill få mer inspiration om vad du kan göra med matplotlib så kolla på denna cheat sheet som kan vara användbar. Även om det är ont om fullständiga exempel så kan vissa attribut användas direkt medan andra mer komplicerade saker kan användas för att söka sig vidare efter information.

Uppgift: Projektuppgift, del 3

Omvandla dictionary till listor

Innan du ritar ett diagram behöver du omvandla dina dictionaries till listor – men kontrollera att platserna finns i samma ordning i båda dictionaries. Dictionaries är i nyare versioner av Python oftast ordnade, men det är inte garanterat om de har olika ursprung.

För att vara säker kan du iterera över platserna i en gemensam lista:

Dina data är sparade som dictionaries, t.ex.:

Kodexempel:

medel_temp = {"Göteborg": 16.7, "Borås": 19.3, "Alingsås": 18.6, "Lerum": 16.5, "Kungsbacka": 15.5}
medel_nederbörd = {"Göteborg": 3.0, "Borås": 3.4, "Alingsås": 4.1, "Lerum": 5.6, "Kungsbacka": 4.0}

För att skapa diagram behöver du två listor – en med platser och en med värden. Du kan enkelt omvandla dina dictionaries så här:

Kodexempel:

platser = list(medel_temp.keys())
temp = [medel_temp[plats] for plats in platser]
nederbörd = [medel_nederbörd[plats] for plats in platser]

Dessa listor kan du sedan använda i dina diagram. Du har tidigare i momentet bearbetat klimatdata till två dictionaries:

  • medel_temp - medeltemperatur per plats
  • medel_nederbörd - medelnederbörd per plats

I denna uppgift ska du visualisera båda dessa med hjälp av matplotlib. Du väljer själv om du vill skapa:

  • två separata diagram (ett för temperatur och ett för nederbörd)
  • ett kombinerat diagram med två y-axlar

Så här skulle ett kombinerat diagram kunna se ut:

Diagram

Diagram
TIPS:
  • Se till att axlarna är tydliga och korrekt färgkodade.
  • Använd tight_layout() så att inget klipps bort.
  • Vill du visa två separata diagram? Använd två plt.figure() eller kör koden två gånger med olika figurer.

6.5 Läsning och lagring av data i CSV-filer

I detta avsnitt kommer du att lära dig hur du arbetar med CSV-filer i Python på ett grundläggande och praktiskt sätt. Du kommer att få läsa in data från en CSV-fil, bearbeta informationen med hjälp av listor och dictionaries samt spara bearbetat data tillbaka till en ny CSV-fil. Dessutom får du lära dig hur du öppnar och exporterar filer med Google Sheets eller Excel.

Vi använder endast inbyggda Python-moduler, vilket betyder att du inte behöver installera några extra bibliotek för att kunna genomföra momenten.

6.5.1 Vad är en CSV-fil?

En CSV-fil (Comma-Separated Values) är en enkel textfil där varje rad representerar en post och varje värde separeras med till exempel kommatecken eller semikolon. CSV används för att spara tabellformad data och kan enkelt öppnas i program som Google Sheets, Excel eller läsas direkt i Python.

Exempel på innehåll i en CSV-fil

klass,namn,poäng
TE21,Alva,85
TE21,Leo,73
NA22,Maja,91
NA22,Elias,88

Observera: I Sverige används ibland semikolon (;) istället för kommatecken på grund av decimalformatering. Modulen csv är inbyggd i Python – du behöver inte installera något extra.

6.5.2 Läsa från CSV-fil i Python

Vi använder modulen csv och verktyget pprint för att läsa och skriva ut datan på ett lättläst sätt.

Kodexempel: Läs in en CSV-fil

import csv
from pprint import pprint  # Importera pretty print för snyggare utskrift

with open("resultat.csv", encoding="utf-8") as fil:
    reader = csv.DictReader(fil, delimiter=",")  # Skapa en reader-objekt (välj ";" om din fil använder semikolon)
    data = list(reader)  # Läs in alla rader som en lista av dictionaries

pprint(data)  # Snygg och lättläst utskrift av listan

Utskrift

[
  {"klass": "TE21", "namn": "Alva", "poäng": "85"},
  {"klass": "TE21", "namn": "Leo", "poäng": "73"},
  {"klass": "NA22", "namn": "Maja", "poäng": "91"},
  {"klass": "NA22", "namn": "Elias", "poäng": "88"}
]

Alla värden läses som strängar. Om du behöver göra beräkningar på t.ex. poäng måste du konvertera dem till heltal (int). För att konvertera fältet "poäng" från sträng till heltal i hela listan kan du använda en for-loop:

Kodexempel: Konvertera poäng till int

for elev in data:
    elev["poäng"] = int(elev["poäng"])

Nu kan du göra uträkningar som medelvärde, högsta och lägsta poäng direkt på heltal istället för strängar.

Modulen pprint (pretty print) används för att skriva ut komplexa datastrukturer på ett snyggt och lättläst sätt. Du kan också anpassa hur datan skrivs ut, t.ex. genom att styra radbrytning och indrag.

Kodexempel: Användning av pprint

pprint(data, width=60)  # Begränsar radens längd för ännu snyggare layout
pprint(data, indent=4)  # Lägger till extra indrag för bättre läsbarhet

Det kan vara extra hjälpsamt om listorna är stora eller innehåller mycket information.

Uppgift: m06u19

Läs in en CSV-fil med 200 provresultat från 5 olika klasser.

  • Beräkna medelpoäng, högsta och lägsta poäng per klass.
  • Konvertera "poäng" till heltal innan beräkningarna.
  • Skriv ut resultatet på skärmen med snygg formatering.

Ladda ner filen m06u19_data.csv.

6.5.3 Skriva till CSV-fil i Python

Efter att ha bearbetat datan kan du skriva resultatet till en ny CSV-fil. Vi använder modulen csv och klassen DictWriter för att skriva en lista av dictionaries till en fil.

Kodexempel: Spara sammanfattning till CSV

import csv

# Skapa en lista med sammanfattningsdata
sammanfattning = [
    {"klass": "TE21", "medel": 79, "högst": 85, "lägst": 73},
    {"klass": "NA22", "medel": 89, "högst": 91, "lägst": 88}
]

# Öppna en ny fil för skrivning
with open("sammanfattning.csv", mode="w", newline="", encoding="utf-8") as fil:
    writer = csv.DictWriter(fil, fieldnames=["klass", "medel", "högst", "lägst"])  # Skapa ett skriv-objekt och ange kolumner
    writer.writeheader()  # Skriv ut rubrikraden i filen
    writer.writerows(sammanfattning)  # Skriv ut alla dictionaries som rader i filen

Förklaring till koden

  • DictWriter skapar ett skriv-objekt där vi bestämmer ordningen på kolumnerna (fieldnames).
  • writeheader() skriver rubrikraden i filen.
  • writerows() skriver varje dictionary som en rad i CSV-filen.
  • newline="" förhindrar extra tomrader i filen (särskilt viktigt på Windows).
  • encoding="utf-8" ser till att svenska tecken som å, ä och ö fungerar korrekt.

Kolumnordningen i fieldnames styr hur datan sparas. Dubbelkolla alltid att alla dictionaries i listan har samma nycklar som fieldnames, annars får du fel.

Resultat i filen sammanfattning.csv

klass,medel,högst,lägst
TE21,79,85,73
NA22,89,91,88

Uppgift: m06u20

Spara en sammanfattning av resultaten från uppgift m06u19 till en ny CSV-fil med rubrikrad. Sammanställningen ska visa medelpoäng, högsta och lägsta poäng för varje klass.

Obs: Börja med att läsa in filen resultat.csv från uppgift m06u19 om du inte redan har datan i minnet.

  • Använd rubrikrad mha writeheader().
  • Spara filen som "sammanfattning.csv".
  • Öppna filen i Google Sheets enligt instruktionen nedan och kontrollera formatet.

6.5.4 Arbeta med CSV i Google Sheets och Excel

När du har sparat en CSV-fil är det enkelt att öppna den i Google Sheets eller Excel för att kontrollera att datan ser korrekt ut.

6.5.4.1 Öppna en CSV-fil i Google Sheets

Öppna en CSV-fil i Google Sheets

  • Gå till Google Drive
  • Klicka på "+ Ny" -> "Filuppladdning".
  • Välj din sparade CSV-fil och ladda upp den.
  • Högerklicka på filen -> välj "Öppna med" -> "Google Kalkylark".

Filen öppnas nu som ett kalkylark där varje kolumn motsvarar ett fält från CSV-filen.

6.5.4.2 Vanliga problem och lösningar

Problem: All data hamnar i en enda kolumn.

Orsak: Google Sheets kan ha missförstått vilken avgränsare som används (komma eller semikolon).

Lösning:

  • Skapa ett nytt tomt kalkylark.
  • Gå till Arkiv -> Importera -> Ladda upp din CSV-fil.
  • I importinställningarna välj rätt avgränsare:
    • Komma om filen använder kommatecken.
    • Semikolon om filen använder semikolon.

Tips: Python sparar som standard med komma som avgränsare om du inte angett något annat.

6.5.4.3 Varning vid redigering och export

Om du redigerar en CSV-fil i Google Sheets och vill spara om den:

  • Gå till Arkiv → Ladda ner → Kommaavgränsad CSV (.csv, aktuellt blad).
  • Se till att du sparar endast det aktuella bladet.
  • Var försiktig med ändringar av talformat och datumformat – det kan påverka hur filen läses tillbaka i Python.

6.5.4.4 Exportera från Google Sheets till CSV

Om du fått en färdig fil i Google Sheets (t.ex. från projektuppgiften) och vill använda den i Python:

  1. Öppna kalkylarket i Google Sheets.
  2. Klicka på Arkiv -> Ladda ner -> Kommaavgränsad CSV (.csv, aktuellt blad).
  3. Filen sparas som en vanlig CSV-fil som kan läsas in i Python med csv.DictReader.

Uppgift: Projektuppgift, del 4

I denna projektuppgift arbetar du vidare med ett större dataset från ett klimatprojekt.

Du får tillgång till en CSV-fil som innehåller dagliga mätningar från åtta orter i Västra Götaland under januari till mars.

Överblick – Det här ska du göra

  • Läsa in klimatdata från en CSV-fil.
  • Bearbeta datan: räkna ut medelvärden och hitta extremvärden.
  • Skapa flera olika typer av diagram.
  • Spara en sammanfattning till en ny CSV-fil.
  • Kontrollera resultatet i Google Sheets.

Datafilen heter "klimatdata_jan_mars.csv" och innehåller:

  • plats, ortens namn
  • datum, i formatet ÅÅÅÅ-MM-DD
  • temp, medeltemperatur i grader Celsius (kan vara negativ)
  • nederbörd, i millimeter

Totalt innehåller filen cirka 700 mätvärden.

Steg-för-steg-instruktion

  1. Läs in datan
    • Använd csv.DictReader för att läsa in filen.
    • Konvertera "temp" och "nederbörd" till float så att du kan räkna med värdena.
  2. Bearbeta datan
    • Beräkna medeltemperatur per ort.
    • Beräkna medelnederbörd per ort.
    • Hitta högsta och lägsta temperatur per ort.
    • Filtrera ut alla dagar där nederbörden var större än 10 mm.
    • Tips: använd dictionaries för att samla information per ort.
  3. Skapa diagram
    • Stapeldiagram över medeltemperatur per ort.
    • Stapeldiagram över medelnederbörd per ort.
    • Kombinerat diagram:
      1. Nederbörd som staplar.
      2. Temperatur som linje med punkter.
      3. Använd två separata y-axlar (twinx())

      Glöm inte att använda tight_layout() för snyggare diagram.

  4. Spara en sammanfattning till CSV
    • Skapa en ny lista av dictionaries där varje rad innehåller:
      • Ortens namn
      • Medeltemperatur
      • Medelnederbörd
      • Högsta temperatur
      • Lägsta temperatur
    • Använd csv.DictWriter för att skriva till en ny fil, t.ex. "sammanfattning_klimat.csv".
  5. Kontrollera resultatet
    • Öppna din sparade CSV-fil i Google Sheets.
    • Kontrollera att alla rubriker och värden ligger rätt.

Tips och påminnelser

  • Arbeta strukturerat: använd gärna funktioner för att hålla koden tydlig.
  • Skriv ut mellanresultat för att kontrollera att allt fungerar innan du bygger vidare.
  • Var noga med filkodning (encoding="utf-8") och avgränsare om du öppnar filen i Google Sheets.
  • Se till att diagrammen får tydliga rubriker och etiketter på axlarna.

Datafilen klimatdata_jan_mars.csv.

Tips för snyggare diagram

För att undvika att ortnamn överlappar eller skärs av, använd följande:

  • plt.xticks(rotation=30) för att rotera x-axelns etiketter om ortsnamnen överlappar eller skärs av.
  • plt.grid(axis="y") för att lägga till horisontella hjälplinjer.
  • plt.tight_layout() för att justera marginalerna automatiskt.
  • figsize=(10, 6) om du vill göra bilden större.

När du är klar med uppgiften så säg gärna till läraren och visa upp din lösning.