Innleveringsoppgave 4 INF109 Dataprogrammering for naturvitskap Dette er den fjerde av syv obligatoriske oppgaver. Du kan få totalt 15 poeng på denne oppgaven. Innleveringsfristen er: Date to be decided. Oppgaven skal leveres inn som én enkelt.py-fil. Oppgaven skal leveres inn på kursets hjemmeside på Mi Side. Oppgavene skal løses individuelt selv om samarbeid er tillatt. Lykke til! 1 Introduksjon Denne uken skal du lage et program som tegner et boksplot over forskjellige værdata fra de samme datafilene som vi brukte i Innleveringsoppgave 2. Brukeren skal velge hvilke fil, hvilket årstall og hvilke datatype (temperatur, vind, etc.) som skal vises. Når brukeren har valgt fil, årstall og kolonne, skal du regne ut diverse data for hver måned i det valgte året. Du kan anta at alle månedene er 30 dager, så det vi egentlig gjør er å lage en oversikt over tolv 30-dagersperioder. Et boksplot er en graf som viser for hvert x-punkt fem forskjellige verdier på y-aksen, nemlig minimum, maksimum, median, bunnkvartil og toppkvartil. Minimum-, maksimum-, og medianverdiene er det det høres ut som, mens bunnkvartilen er den verdien som er slik at 25% av verdiene er lavere eller lik, mens toppkvartilen er den verdien slik at 25% av verdiene er høyere eller lik. Siden det (nå) er 30 dager i hver måned, kan du anta bunnkvartilen er den 7 laveste verdien og toppkvartilen den 7 høyeste (en approksimasjon). (Du kan gjerne bla frem allerede for å se på bildene.) 1.1 Oversikt (les nøye) Oppgave 1 ber deg om å lage funksjonen som tegner de individuelle boksplottene, Oppgave 2 ber deg om å lage en funksjon som returnerer en kvintuppel (minimum, maksimum, median, bunnkvartil, toppkvartil) gitt en liste av verdier. I Oppgave 3 skal du lage en funksjon som tar inn et årstall og en kolonne og leser 360 dager fra det årstallet, og kaller funksjonen i Oppgave 2 for hver 30. dag. Til slutt, i Oppgave 4, skal du lage en funksjon som ber en bruker om å skrive inn filnavn, årstall og kolonne, og skal lage et vindu som viser alle dataene. Alle oppgavene blir laget etter hverandre og uavhengig, slik at vi alltid kan teste at alt fungerer som forventet underveis. 2 Forberedelser Før du starter er det greit å ha på plass filene verdata florida.txt, verdata kirkenes.txt og graphics.py i katalogen du jobber i. 1
Forestill deg følgende kommunikasjon mellom program og bruker (brukeren skriver først inn filnavn, verdata florida.txt, deretter årstall, 1994 og tilslutt kolonnenummer, 4): 2
Velg datafil : verdata_florida. txt Laster fil... ferdig Velg aar : 1994 1: DD06 2: DD12 3: DD18 4: FFM 5: FXM 6: POM 7: TAM 8: UUM Velg data [1-8]: 4 Prosesserer data 4 ( FFM ) For hver 30-dagersperiode skal programmet regne ut gjennomsnittet av dataene, og for hver 360- dagersperiode skal programmet regne ut minimumverdi, maksimumverdi, median, nedre kvartile og øvre kvartile. Deretter skal programmet plotte disse verdiene. Vi skal begynne med å lage den funksjonen som har som oppgave å tegne firkantene i vinduet. Når det er gjort, gjenstår det bare å regne ut de forskjellige verdiene, men det er bagateller. Oppgave 1 Lag en metode plotboks(vindu, x, minimum, maksimum, median, bunnkvartil, toppkvartil) som i vinduet vindu, på x-koordinat x tegner horisontale streker hvor medianen, minimumog maksimumverdien er, og tegner et rektangel 1 med toppunkt toppkvartil og bunnpunkt bunnkvartil. Du kan anta at x-aksen er satt slik at alle horisontale streker kan gå fra x 0.33 til x + 0.33. Begynn med å lage plotboks med signatur som beskrevet over, og test denne funksjonen ved å skrive følgende (se Figur 1): >>> vindu = GraphWin (" BoxPlot ", 1000, 600) >>> vindu. setcoords (0,0,12,50) >>> plotboks ( vindu, 5, 10, 40, 25, 20, 35) Du kan også teste funksjonen ved å plotte tilfeldige data. En mulighet er å gjøre som følger: 2 >>> vindu = GraphWin (" BoxPlot ", 1000,600) >>> vindu. setcoords (0,0,12,50) >>> from random import sample >>> for x in range (1,12) :... data = sample ( range (1,50), 5)... data. sort ()... plotboks ( vindu, x, data [0], data [4], data [2], data [1], data [3]) 1 Dersom du ikke vet hvordan du lager et rektangel med Rectangle(p1, p2), kan du tegne det manuelt ved å tegne fire streker. 2 Prøv å forstå hva som skjer. Et hint er at sample slik den er brukt i koden gir fem tilfeldige og forskjellige verdier mellom 1 og 50, og data.sort() sorterer tallene i listen data i stigende rekkefølge. Se Figur 2. 3
Figure 1: Vindu med en boks. Figure 2: Vindu med mange tilfeldige bokser. 4
Oppgave 2 I denne oppgaven skal du lage en metode som returnerer en kvintuppel (minimum, maksimum, median, bunnkvartil, toppkvartil), gitt en liste av verdier. Her er et eksempel på hvordan man lager og sorterer en liste: >>> minliste = [8,5,4,6,9,7,10,2,5,3,15,6,9,7,8,7,5,1,1,1,2,14,2,3,4,6,4,2,4,9] >>> len ( minliste ) 30 >>> minliste. sort () >>> print ( minliste ) [1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 14, 15] Som du ser, er listen minliste nå sortert, og det er enkelt å hente ut minimums- og maksimumsverdien. De er, respektivt, minliste[0] og minliste[29] 3. Medianen er også enkel, den er minliste[14] + minliste[15], 2 men for enkelthetsskyld velger vi idag medianen til å være minliste[14]. Bunn- og toppkvartilen er altså den verdien som er slik at 25% av verdiene er lavere (resp. høyere); Du klarer nok å finne ut hva som skal erstatte b og t i bunnkvartil = minliste[b] og toppkvartil = minliste[t]. Når vi har fått oversikt over hvordan vi skal få tak i de forskjellige verdiene, lager vi funksjonen som er beskrevet under: def regn_verdier ( inndata ): """ Tar inndata, som er en liste av 30 elementer, sorterer den og returnerer minimum, maksimum, median og de to kvartilene som en kvintuppel. """ inndata. sort () # here be dragons return ( minimum, maksimum, median, bunnkvartil, toppkvartil ) Til slutt kan vi verifisere at funksjonen vår fungerer som antatt ved å gjøre som følger (minliste er som i eksempelet over): >>> print ( regn_verdier ( minliste )) (1, 15, 5, 2, 8) Dersom du ønsker kan du også teste å tegne dataene i vinduet ved å gjøre følgende: >>> kvintuppel = regn_verdier ( minliste ) >>> minimum = kvintuppel [0] # minimum blir satt til foerste element i tuppelen >>> maksimum = kvintuppel [1] >>> median = kvintuppel [2] >>> bunnkvartil = kvintuppel [3] >>> toppkvartil = kvintuppel [4] >>> plotboks ( vindu, x, minimum, maksimum, median, bunnkvartil, toppkvartil ) 3 Du kan også bruke minliste[-1] for å få ut siste elementet i listen minliste. 5
Oppgave 3 I denne oppgaven skal du lage en metode som tar inn en fil, et årstall og et kolonnetall, og som leser 12 perioder á 30 dager og for hver 30. dag kaller funksjonen i Oppgave 2 og legger resultatet i en liste som heter maanedsdata. Den listen inneholder tilslutt 12 elementer (faktisk 12 kvintupler), og den skal returneres til slutt. def behandle_ett_aar ( filnavn, aarstall, kol ): """ Aapner filen filnavn og hopper frem til korrekt aarstall, og leser 360 verdier fra kolonnen kol. Returnerer tilslutt kvintuplene for hver 30 - dagersperiode. """ innfil = open ( filnavn, r ) for i in range (( aarstall -1957) * 365) : # vi spoler frem til riktig aar ved aa ignorere begynnelsen av filen innfil. readline () maanedsdata = [0]*12 for maaned in range (12) : dager = [0]*30 for dag in range (30) : # her skjer magi maanedsdata [ maaned ] = regn_verdier ( dager ) innfil. close () return maanedsdata La oss teste funksjonen ved å la den skrive ut alle kvintuplene som hører til 1994 4. >>> for kvint in behandle_ett_aar (" verdata_florida. txt ", 1994, 4):... print ( kvint ) (0, 360, 150, 70, 180) (0, 320, 130, 0, 170) (30, 320, 150, 90, 250) (110, 340, 160, 130, 270) (90, 350, 300, 160, 320) (0, 350, 270, 150, 310) (110, 330, 230, 160, 320) (130, 340, 310, 160, 320) (0, 360, 290, 140, 320) (0, 340, 160, 120, 310) (0, 340, 150, 130, 300) (90, 350, 160, 130, 280) 4 Ved vår forenklede måte å regne oss frem til årstall, bommer vi nok litt på 1994, men bare så vidt. Alternativet hadde vært å parse datoen i filen, men dette får bli til en annen innleveringsoppgave. 6
Du kan også prøve med andre kolonnenumre: >>> for kvint in behandle_ett_aar (" verdata_florida. txt ", 1994, 6):... print ( kvint ) (2.1, 14.2, 5.3, 2.8, 8.9) (1.3, 13.7, 2.4, 1.7, 7.5) (2.1, 11.0, 5.8, 4.8, 8.6) (3.8, 15.4, 7.5, 5.6, 9.6) (3.2, 8.4, 5.0, 4.1, 7.4) (3.4, 8.4, 6.0, 4.9, 6.9) (3.1, 8.4, 4.6, 3.6, 6.4) (2.8, 9.8, 4.4, 3.8, 6.2) (2.4, 12.2, 4.6, 3.3, 6.7) (1.3, 8.9, 5.7, 3.4, 7.5) (1.9, 10.1, 4.8, 2.8, 7.9) (1.9, 16.4, 5.8, 4.1, 9.6) Nå kan du kanskje se hvordan programmet faller på plass, allerede etter tre ganske enkle metoder. Det eneste som gjenstår nå er å hente inn informasjon fra brukeren, lage et vindu, og så tegne alle tolv kvintuplene ved hjelp av plotboks. Oppgave 4 Nå skal vi lime sammen programmet. Du skal lage metoden main som ikke tar inn noen argumenter. Den skal gjøre som eksempelet over. Husk at når brukeren velger kolonnenummer k, så må du sannsynligvis bruke k-1, k+1 eller noe tilsvarende (men dette må du tenke ut selv). I tillegg vet vi ikke hvordan koordinatsystemet til vinduet skal være; Da vi brukte kolonnenummer 6, så vi at tallene i 1994 gikk fra 1.3 til 16.4, mens for kolonnenummer 4 så vi verdier fra 0 til 360. Det kan også tenkes at dersom man finner temperaturer, kan de til og med bevege seg under 0. Det skal ikke være så vanskelig for en erfaren programmerer å finne minimum av minimumsverdiene og maksimum av maksimumsverdiene for å bruke i koordinatsystemet. Ps. dersom du setter x-aksen til å gå fra 0 til 12.5, får du med hele siste boksen uten noen problemer. def main (): """ Ber bruker om filnavn, aarstall, kolonnenummer. Prosesserer dataene, lager og aapner et vindu, og til slutt tegner alle boksene i vinduet. Programmet avslutter naar brukeren trykker i vinduet. """ # do your thing vindu. getmouse () Dersom du har kommet hit kan du puste lettet ut. Du er ferdig! 7
Minimumstemperaturen var -4.9 C, maksimums- Figure 3: Temperaturer i Bergen i 1994. temperaturen var 22.5 C. 8
3 Innlevering Lagre programmet ditt i en.py-fil som heter oblig4-abc123.py, hvor abc123 skal erstattes med ditt brukernavn, og lever besvarelsen på studentportalen Mi Side, i mappen 4 Vurdering Innleveringsmappe Vurderingsmappe Innlevering 4. For denne oppgaven kan du få maksimalt 15 poeng. Fordeling av poeng er som følger. Programmet fungerer som forventet 12 (ca. 4 3) Programmet er veldokumentert med kommentarer og oversiktlig 2 Navngiving 1 15 Programmet fungerer som forventet. Her får man trekk om programmet enten skriver ut feil data, har feil format på utskrift (avviker fra eksempelet), kræsjer på noen som helst måte eller om metodenavn ikke er som oppgitt. Programmet er veldokumentert med kommentarer og oversiktlig. Her får man trekk om programmet ikke er kommentert godt nok, men også om programmet er for mye kommentert. Man kan også få trekk om programmet er uoversiktlig. Navngiving. Her får man trekk dersom navn på variabler og metoder ikke er fornuftig valgt og at navngivingen som er brukt er inkonsistent. Husk å velge enten mixedcase eller underscore. 5 Oppgavene vil være ferdigrettet innen én uke har gått, og poengsum og kommentarer fra retter vil bli postet i vurderingsmappen under kommentarer. Spørsmål til rettingen kan bli rettet til en av gruppelederne, eventuelle klager skal rettes til koordinator på e-post (email to be decided) som vil se gjennom rettingen og eventuelt be en annen gruppeleder rette på ny. Obs: Den nye karakteren vil bli stående og det er ikke garantert at den ikke vil gå ned. 5 mixedcase er når variablene ser ut som innlestdata, mens underscore er når variablene skrives som innlest data. Velg én av disse to, og hold dere til den måten. I boken bruker de førstnevnte, mens det er kanskje vanligere ellers i Python-verdenen å bruke sistnevnte. Aldri begynn med stor forbokstav, e.g. InnlestData eller lignende, da disse er reservert til klassenavn, noe som er delvis utenfor pensum for dette kurset. 9