Visualisering av kjemiske data#

Læringsutbytte

Etter å ha arbeidet med dette temaet, skal du kunne:

  1. velge en visualisering som passer til kjemiske data

  2. bruke Matplotlib til å lage punkt- og linjeplott

  3. lage figurer med aksetitler, enheter, tegnforklaring og hensiktsmessig skalering

  4. visualisere flere dataserier og flere plott i samme figur

  5. forklare hva en figur viser, og hva den ikke viser

Håndtering av data blir bare viktigere og viktigere. En viktig del av datahåndtering er å kunne lage informative figurer som beskriver dataene på en god måte. Programmering gir oss stor kontroll over hvordan dataene behandles og visualiseres, og gjør det mulig å gjenta den samme framgangsmåten når vi får nye data.

En figur er likevel ikke bare pynt. Valg av plott, akser og skala påvirker hvilke mønstre vi legger merke til. En god kjemisk figur skal gjøre det lettere å svare på et faglig spørsmål.

Datavisualisering

Datavisualisering betyr å framstille data grafisk slik at mønstre, variasjon og sammenhenger blir lettere å undersøke og formidle.

Før vi velger figur, bør vi derfor spørre:

  • Hva representerer hvert datapunkt?

  • Hvilken variabel har vi kontrollert, og hvilken har vi målt?

  • Er datapunktene uavhengige, eller følger de en naturlig rekkefølge?

  • Skal figuren vise rådata, en oppsummering eller en modell?

Punktplott av måledata#

Hvis vi har få datapunkter, kan vi skrive dem inn i lister direkte i programmet. Vi tar utgangspunkt i et eksempel der damptrykket til vann er målt ved ulike temperaturer:

Temperatur (°C)

Damptrykk (kPa)

16

1,817

18

2,063

20

2,339

22

2,644

24

2,984

import matplotlib.pyplot as plt

temperature_C = [16, 18, 20, 22, 24]
vapor_pressure_kPa = [1.817, 2.063, 2.339, 2.644, 2.984]

plt.scatter(temperature_C, vapor_pressure_kPa)
plt.xlabel("Temperature (°C)")
plt.ylabel("Vapor pressure (kPa)")
plt.show()

Funksjonen scatter lager et punktplott. Hvert punkt kobler sammen én temperatur og det tilhørende damptrykket. Dette er måledata: Temperaturen er den uavhengige variabelen vi har valgt, mens damptrykket er den avhengige variabelen vi har målt.

Det er viktig at listene har like mange elementer. Elementer med samme indeks hører sammen. Den første temperaturen kobles til det første damptrykket, den andre temperaturen til det andre damptrykket, og så videre.

Enheter og aksetitler#

En figur uten aksetitler og enheter er vanskelig å tolke. xlabel og ylabel brukes til å beskrive hva aksene viser. Enheten bør stå i parentes. Selve tallene i datasettet skal normalt ikke inneholde enhetstekst, fordi Python da ikke lenger kan behandle dem som tall.

Vi kan også legge til tittel, rutenett, merkelapp og tegnforklaring:

import matplotlib.pyplot as plt

temperature_C = [16, 18, 20, 22, 24]
vapor_pressure_kPa = [1.817, 2.063, 2.339, 2.644, 2.984]

plt.scatter(temperature_C,
    vapor_pressure_kPa,
    color="#176b87",
    s=55,
    label="Measurements")
plt.xlabel("Temperature (°C)")
plt.ylabel("Vapor pressure (kPa)")
plt.title("Vapor pressure of water")
plt.grid(alpha=0.25)
plt.legend()
plt.tight_layout()
plt.show()

tight_layout justerer avstanden mellom elementene slik at for eksempel aksetitler ikke blir kuttet. Farge og punktstørrelse kan gjøre figuren tydeligere, men utformingen bør ikke overdøve dataene.

Du kan kjøre og endre damptrykksprogrammet i editoren nedenfor.

Underveisoppgave

  1. Endre farge og punktstørrelse.

  2. Fjern én av aksetitlene. Hvilken informasjon går tapt?

  3. Utvid datasettet med en måling ved 26 °C og 3,36 kPa.

  4. Bytt om listene i plt.scatter. Hvordan endrer det den faglige framstillingen?

Skal punktene bindes sammen?#

Funksjonen plot tegner som standard linjer mellom punktene. Det kan være hensiktsmessig når dataene følger en naturlig rekkefølge, for eksempel en tidsserie:

import matplotlib.pyplot as plt

time_s = [0, 10, 20, 30, 40, 50, 60]
absorbance = [0.812, 0.673, 0.552, 0.458, 0.378, 0.313, 0.260]

plt.plot(time_s, absorbance, marker="o")
plt.xlabel("Time (s)")
plt.ylabel("Absorbance")
plt.title("Absorbance during a reaction")
plt.show()

Her viser linja rekkefølgen på målingene og gjør tidsutviklingen lettere å følge. Linja betyr likevel ikke at vi har målt alle tidspunktene mellom punktene. Den er en visuell forbindelse, ikke i seg selv en kontinuerlig kjemisk modell.

For kalibreringsstandarder er et punktplott ofte et bedre utgangspunkt. Standardene er selvstendige prøver, og en eventuell linje bør komme fra en regresjonsmodell. Vi bør ikke la plot koble dem sammen bare fordi de står i stigende rekkefølge.

Huskeregel

Bruk punktplott når du vil vise enkeltmålinger og sammenhengen mellom to størrelser. Bruk linjer når rekkefølgen mellom punktene er viktig, eller når linja representerer en eksplisitt modell.

Du kan undersøke tidsserien i editoren nedenfor.

Underveisoppgave

  1. Bytt plt.plot med plt.scatter. Hva blir lettere eller vanskeligere å se?

  2. Fjern markørene fra linjeplottet. Hvilken informasjon blir mindre tydelig?

  3. Beskriv den kjemiske utviklingen i figuren uten å hevde mer enn dataene viser.

Flere dataserier i samme figur#

Vi kan sammenlikne dataserier ved å plotte dem i samme koordinatsystem. Da må de få ulike markører eller linjestiler og tydelige merkelapper:

import matplotlib.pyplot as plt

time_s = [0, 20, 40, 60, 80, 100]
absorbance_298_K = [0.812, 0.552, 0.378, 0.260, 0.181, 0.128]
absorbance_308_K = [0.809, 0.476, 0.284, 0.172, 0.108, 0.071]

plt.plot(time_s, absorbance_298_K, marker="o", label="298 K")
plt.plot(time_s, absorbance_308_K, marker="s", label="308 K")
plt.xlabel("Time (s)")
plt.ylabel("Absorbance")
plt.title("Reaction at two temperatures")
plt.legend()
plt.tight_layout()
plt.show()

En god tegnforklaring gjør det mulig å skille dataseriene uten å være avhengig av farge alene. Dette er viktig både ved utskrift i gråtoner og for personer med redusert fargesyn.

Underveisoppgave

Hvilken reaksjonsblanding ser ut til å reagere raskest? Er figuren alene tilstrekkelig til å konkludere med at temperatur er årsaken til forskjellen?

Flere plott i samme figur#

Noen ganger blir én akse overfylt. Da kan vi bruke subplots til å lage flere akser i samme figur:

import matplotlib.pyplot as plt

time_s = [0, 20, 40, 60, 80, 100]
absorbance_298_K = [0.812, 0.552, 0.378, 0.260, 0.181, 0.128]
absorbance_308_K = [0.809, 0.476, 0.284, 0.172, 0.108, 0.071]

fig, axes = plt.subplots(1, 2, figsize=(10, 4), sharey=True)

axes[0].plot(time_s, absorbance_298_K, marker="o")
axes[0].set_title("298 K")
axes[0].set_xlabel("Time (s)")
axes[0].set_ylabel("Absorbance")

axes[1].plot(time_s, absorbance_308_K, marker="s", color="#b23a48")
axes[1].set_title("308 K")
axes[1].set_xlabel("Time (s)")

fig.suptitle("Reaction at two temperatures")
fig.tight_layout()
plt.show()

Variabelen axes inneholder de to koordinatsystemene. Vi bruker axes[0] for den første og axes[1] for den andre. sharey=True gir dem samme y-akse, slik at kurvene kan sammenliknes visuelt uten at skalaen endres.

Aksegrenser og visuell redelighet#

Aksegrensene kan justeres med xlim og ylim, men valget må være faglig begrunnet:

plt.ylim(0, 0.9)

En svært smal y-akse kan få små forskjeller til å virke dramatiske. En svært bred akse kan skjule reelle variasjoner. Det finnes ikke én riktig grense for alle figurer, men leseren må få et ærlig bilde av størrelsene og variasjonen.

Logaritmiske akser kan være nyttige når verdiene dekker flere størrelsesordener. De skal merkes tydelig og brukes fordi de hjelper oss å undersøke et faglig spørsmål, ikke bare fordi figuren ser penere ut.

Hva er en god kjemisk figur?#

Før du avslutter en figur, kan du kontrollere følgende:

  • Er datapunktene eller modellen som vises, tydelig identifisert?

  • Har begge aksene navn og enhet?

  • Er skalaen hensiktsmessig og redelig?

  • Kan dataseriene skilles uten bare å bruke farge?

  • Er tegnforklaringen nødvendig og forståelig?

  • Viser figuren rådata, middelverdier eller en modell?

  • Dersom figuren har feilstolper: Er det oppgitt hva de representerer?

  • Kan du formulere en kjemisk tolkning uten å overtolke dataene?

Oppgaver#

Oppgave 1.1

Lag et punktplott av temperaturene [10, 20, 30, 40, 50] °C og løselighetene [21.2, 31.6, 45.8, 63.9, 85.5] g per 100 g vann. Gi figuren aksetitler, enheter og en faglig tittel.

Oppgave 1.2

Tegn løselighetsdataene fra oppgave 1.1 både med scatter og plot. Forklar hvilken versjon du foretrekker, og hva linja mellom punktene eventuelt antyder.

Oppgave 1.3

Programmet nedenfor lager en figur som er vanskelig å tolke. Finn minst fire forbedringer.

import matplotlib.pyplot as plt

x = [0, 1, 2, 3, 4]
y = [7.02, 6.81, 6.60, 6.42, 6.25]

plt.plot(y, x, color="yellow")
plt.title("Results")
plt.show()

Oppgave 1.4

Les fila reaction_kinetics.csv med Pandas og visualiser absorbansen som funksjon av tid. Bruk både punkter og linje. Beskriv utviklingen med kjemiske ord.

Oppgave 1.5

Lag to realistiske dataserier som viser absorbansen gjennom en reaksjon ved to temperaturer. Vis seriene i samme koordinatsystem og deretter i to delplott. Diskuter hvilken figur som gjør sammenlikningen enklest.

Oppgave 1.6

En student viser gjennomsnittsverdier med feilstolper, men skriver bare «error bars» i figurteksten. Forklar hvorfor dette er utilstrekkelig. Hvilke ulike statistiske størrelser kan feilstolpene representere?

Oppgave 1.7

Lag en figur der en misvisende y-akse får to nesten like måleserier til å se svært forskjellige ut. Lag deretter en mer redelig versjon. Forklar hvilke valg du gjorde.

Oppgave 1.8 – samlet case

Fila uvvis_calibration.csv inneholder blankprøver, kalibreringsstandarder og en ukjent prøve. Lag en første utforskende figur av absorbans som funksjon av konsentrasjon. Vis bare standardene. Hvilken informasjon mister du dersom du først beregner ett gjennomsnitt for hver konsentrasjon?

Video#

I videoen nedenfor kan du få en innføring eller repetisjon i hvordan du plotter i Python.