Cursus

Het kunnen maken van makkelijk te begrijpen én toch verfijnde grafieken is cruciaal om een succesvolle data scientist te worden. Visualisaties zijn een geweldige manier om het onderliggende verhaal in je data te vertellen. Ze laten relaties in de data zien en onthullen informatie die voor het menselijk oog zichtbaar is maar niet met alleen cijfers kan worden overgebracht. Maar weet je wat nog beter is dan visualisaties voor data-analyse? Interactieve visualisaties!
Helaas kan het als beginner een ontmoedigende taak lijken. Python en R bieden allebei een groot scala aan tools en trucs om je te helpen. In deze tutorial maken we je wegwijs in Altair. Met Altair kun je met slechts een paar regels code en in zeer korte tijd betekenisvolle, elegante en effectieve visualisaties maken. Laten we beginnen!
Wat is Altair?
Altair is een Python-bibliotheek voor statistische visualisatie. De aanpak is declaratief van aard (we komen later op deze definitie terug). Het is gebaseerd op Vega en Vega-Lite, beide visualisatiegrammatica’s waarmee je het visuele uiterlijk en interactieve gedrag van een visualisatie kunt beschrijven in een JSON-formaat.
Imperatieve vs. declaratieve API’s
Zoals eerder genoemd heeft Python al een lijst met geweldige tools en bibliotheken voor datavisualisatie, en veel daarvan ondersteunen ook interactieve visualisatie. Maar wat maakt Altair bijzonder?
Het antwoord zit in het declaratieve karakter in vergelijking met andere imperatieve API’s.
Bij imperatieve API’s moet je focussen op ‘hoe je iets doet’ in plaats van ‘wat je wilt doen’. Je denkt meer na over de code die nodig is om de visualisatie te maken en specificeert handmatig de plotstappen: aslimieten, grootte, rotatie, legenda’s, enzovoort.
Als data scientist laat Altair je je tijd en energie richten op je data—begrijpen, analyseren en visualiseren—en niet op de code die daarvoor nodig is. Dit betekent dat je de data en de gewenste output kunt definiëren (hoe de visualisatie er uiteindelijk uit moet zien), en Altair voert de benodigde bewerkingen automatisch voor je uit.
Installatie
In deze tutorial gebruiken we een voorbeeld-dataset uit Vega datasets. Om Altier te installeren, samen met de Vega datasets, typ je het volgende in je consolevenster:
$ pip install altair vega_datasets
Als je de conda package manager gebruikt, is het equivalent:
$ conda install -c conda-forge altair vega_datasets
Daarna kun je naar je Jupyter Notebook gaan en Altair importeren om te beginnen. Wil je meer leren over Jupyter Notebook, bekijk dan zeker de Jupyter Notebook Definitive guide van DataCamp.
Data
Nu we Altair samen met de Vega-dataset hebben geïnstalleerd, is het tijd om wat data te laden. Begin met de volgende imports:
import pandas as pd
import altair as alt
Waarom Pandas importeren?
Omdat data in Altair is opgebouwd rond de Pandas DataFrame, kun je data in Altair manipuleren zoals je met een Pandas-DataFrame zou doen.
En hoewel Altair intern data bewaart in de vorm van een Pandas DataFrame, zijn er meerdere manieren om data aan te leveren:
- als een Pandas DataFrame
- als een Data- of gerelateerd object (zoals UrlData, InlineData, NamedData)
- als een URL-string die verwijst naar een JSON- of CSV-tekstdocument
- als een object dat geo_interface ondersteunt (bijv. Geopandas GeoDataFrame, Shapely Geometries, GeoJSON Objects)
Movies-dataset
In deze tutorial werken we met de Movies-dataset uit de Vega-dataset. Deze of vergelijkbare datasets over films zijn beroemd in de data science-community, vooral in de context van aanbevelingssystemen. Wij gaan echter alleen data-analyse uitvoeren met visualisaties in Altair.
De dataset bevat informatie over films zoals de titel, de opbrengst in Amerika en wereldwijd, samen met het productiebudget, genre, beoordelingen van IMDB en Rotten Tomatoes. We behandelen niet alle kolommen, maar gebruiken er een paar om meer te leren over hoe Altair als visualisatietool werkt.
Laten we verdergaan, de dataset ophalen en wat eenvoudige analyses doen om deze beter te begrijpen.
# Importing the Vega Dataset
from vega_datasets import data as vega_data
movies_df = pd.read_json(vega_data.movies.url)
# Checking the type of data that we get
print("movies_df is of the type: ", type(movies_df))
print("movies_df: ", movies_df.shape)
movies_df is of the type: <class 'pandas.core.frame.DataFrame'>
movies_df: (3201, 16)
Zoals je zag is movies_df eigenlijk een pandas DataFrame en bevat het 3201 films (rijen) met elk 16 kenmerken (kolommen). Laten we de data binnen de dataframe bekijken.
movies_df.head(5)
| Title | US_Gross | Worldwide_Gross | US_DVD_Sales | Production_Budget | Release_Date | MPAA_Rating | Running_Time_min | Distributor | Source | Major_Genre | Creative_Type | Director | Rotten_Tomatoes_Rating | IMDB_Rating | IMDB_Votes | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | The Land Girls | 146083.0 | 146083.0 | NaN | 8000000.0 | Jun 12 1998 | R | NaN | Gramercy | None | None | None | None | NaN | 6.1 | 1071.0 |
| 1 | First Love, Last Rites | 10876.0 | 10876.0 | NaN | 300000.0 | Aug 07 1998 | R | NaN | Strand | None | Drama | None | None | NaN | 6.9 | 207.0 |
| 2 | I Married a Strange Person | 203134.0 | 203134.0 | NaN | 250000.0 | Aug 28 1998 | None | NaN | Lionsgate | None | Comedy | None | None | NaN | 6.8 | 865.0 |
| 3 | Let's Talk About Sex | 373615.0 | 373615.0 | NaN | 300000.0 | Sep 11 1998 | None | NaN | Fine Line | None | Comedy | None | None | 13.0 | NaN | NaN |
| 4 | Slam | 1009819.0 | 1087521.0 | NaN | 1000000.0 | Oct 09 1998 | R | NaN | Trimark | Original Screenplay | Drama | Contemporary Fiction | None | 62.0 | 3.4 | 165.0 |
De kolomwaarden zijn:
movies_df.columns
Index(['Title', 'US_Gross', 'Worldwide_Gross', 'US_DVD_Sales',
'Production_Budget', 'Release_Date', 'MPAA_Rating', 'Running_Time_min',
'Distributor', 'Source', 'Major_Genre', 'Creative_Type', 'Director',
'Rotten_Tomatoes_Rating', 'IMDB_Rating', 'IMDB_Votes'],
dtype='object')
We gaan nu de to_datetime-functie in pandas gebruiken om de kolom Release_Date om te zetten naar een echte datum en daar vervolgens het ‘jaar’ uit te halen. Deze nieuw gemaakte kolom gebruiken we later in onze visualisaties.
def extract_year(value):
return pd.to_datetime(value, format='%b %d %Y').year
movies_df["Year"] = movies_df["Release_Date"].apply(extract_year)
Als je nu de kolomwaarden bekijkt, zie je een nieuwe kolom Year met de jaartallen voor de bijbehorende film.
movies_df.columns
Index(['Title', 'US_Gross', 'Worldwide_Gross', 'US_DVD_Sales',
'Production_Budget', 'Release_Date', 'MPAA_Rating', 'Running_Time_min',
'Distributor', 'Source', 'Major_Genre', 'Creative_Type', 'Director',
'Rotten_Tomatoes_Rating', 'IMDB_Rating', 'IMDB_Votes', 'Year'],
dtype='object')
Nu gaan we een eerste plot maken. Maar voer eerst dit stukje code uit:
alt.renderers.enable('notebook')
RendererRegistry.enable('notebook')
De code hierboven zorgt ervoor dat Altair inline rendert in de Jupyter-notebook, zodat we de figuren die we maken kunnen zien. Loop je tegen problemen aan, bekijk dan de troubleshooting-pagina van Altair.
Bij een eerste blik op de data is het interessant om de relatie te zien tussen hoeveel geld er naar het maken van de film ging (Production_Budget) en hoeveel geld de film daadwerkelijk opbracht (Worldwide_Gross). We zetten deze waarden op de X- en Y-as.
De dataset is echter relatief groot—omdat we ons willen richten op het werken met Altair. Dus werken we voorlopig met slechts een paar datapunten. Laten we kijken hoeveel films er in een bepaald jaar in onze dataset staan en een jaar kiezen om op te focussen.
movies_df["Year"].value_counts()
2006 220
2005 210
2002 208
2004 192
2000 188
...
1943 1
2015 1
2027 1
2037 1
1928 1
Name: Year, Length: 91, dtype: int64
We richten ons op het jaar 2000 en maken een nieuwe dataframe movies_2000 met alleen data uit dit jaar. Deze zou 188 rijen (films) moeten bevatten.
movies_2000 = movies_df[movies_df["Year"] == 2000]
movies_2000.shape
(188, 17)
We werken nu toe naar onze eerste visualisatie. Laten we iets dieper in het formaat van Altair duiken.
Grafieken
Charts zijn een fundamenteel object in Altair en accepteren één argument: een dataframe. Zo definieer je een chart:
alt.Chart(DataFrame)
Maar op zichzelf doet de chart niet veel behalve de data specificeren waarmee je wilt werken; daarna moet je aangeven wat je vervolgens met de data wilt doen. Daarvoor gebruiken we marks.
Marks
Met de mark-eigenschap geef je aan hoe de data in de plot moeten worden weergegeven. Dit zijn de basis mark-eigenschappen in Altair:

Voor de mark-eigenschap willen we dat elke waarde in de DataFrame als een punt (cirkel) in de plot gemarkeerd wordt. Daarom schrijven we:
alt.Chart(DataFrame).mark_point()
Encodings
Als we weten welke data en hoe die wordt weergegeven, willen we ook aangeven waar die wordt weergegeven. Dus de posities, grootte, kleur, enz. instellen. Daarvoor gebruiken we encodings. Dus krijgen we:
alt.Chart(DataFrame).mark_point().encode()
Alles bij elkaar gezet en details toegevoegd om onze eerste visualisatie te maken:
alt.Chart(movies_2000).mark_point().encode(
alt.X('Production_Budget'),
alt.Y('Worldwide_Gross')
)
<vega.vegalite.VegaLite at 0x11709a1d0>

Mooi toch? We hoefden niet veel te doen—een paar begrippen leren en ze samenbrengen. Nu hebben we een plot waarin we zien hoeveel er is uitgegeven vs. hoeveel er is opgebracht door de films in het jaar 2000 uit onze dataset.
Laten we deze grafiek interessanter maken. In plaats van alle punten dezelfde cirkelgrootte te geven, maken we de punten zo groot (of klein) als hun bijbehorende US_Gross. Hiervoor introduceren we de eigenschap Size. Hoe groter de punt, hoe groter de Amerikaanse box-officeopbrengst. Laten we de punten ook inkleuren in plaats van alleen een rand; daarvoor voegen we een argument toe aan de eigenschap mark_point().
alt.Chart(movies_2000).mark_point(filled=True).encode(
alt.X('Production_Budget'),
alt.Y('Worldwide_Gross'),
alt.Size('US_Gross')
)
<vega.vegalite.VegaLite at 0x117cce790>

Nu hebben we in slechts vier regels een plot die de budgetten van elke film weergeeft. Wat mist er nog? KLEUR!
Maar we gaan niet zomaar willekeurige kleuren toevoegen. We houden de grafiek interessant door nog een stukje informatie uit de dataset te gebruiken: Major_Genre. We geven elk filmgenre een eigen kleur met de Color-eigenschap en voegen wat transparantie toe met OpacityValue.
alt.Chart(movies_2000).mark_point(filled=True).encode(
alt.X('Production_Budget'),
alt.Y('Worldwide_Gross'),
alt.Size('US_Gross'),
alt.Color('Major_Genre'),
alt.OpacityValue(0.7)
)
<vega.vegalite.VegaLite at 0x118e3ff50>

Dit is al goed, maar het kan beter! Het zou fijn zijn als we door de plot kunnen bewegen en details kunnen zien over de film die het datapunt vertegenwoordigt. Met Tooltip kan dat…
alt.Chart(movies_2000).mark_point(filled=True).encode(
alt.X('Production_Budget'),
alt.Y('Worldwide_Gross'),
alt.Size('US_Gross'),
alt.Color('Major_Genre'),
alt.OpacityValue(0.7),
tooltip = [alt.Tooltip('Title'),
alt.Tooltip('Production_Budget'),
alt.Tooltip('Worldwide_Gross'),
alt.Tooltip('US_Gross')
]
)
<vega.vegalite.VegaLite at 0x118e3ff90>

Tof hè? Maar wacht, we doen nog meer. Weet je nog waarom we Altair wilden gebruiken? Zodat we interactieve visualisaties kunnen maken. De tooltip biedt al wat interactie wanneer je over de punten zweeft. Laten we echter een simpele interactive()-functionaliteit toevoegen aan wat we al hebben…
alt.Chart(movies_2000).mark_point(filled=True).encode(
alt.X('Production_Budget'),
alt.Y('Worldwide_Gross'),
alt.Size('US_Gross'),
alt.Color('Major_Genre'),
alt.OpacityValue(0.7),
tooltip = [alt.Tooltip('Title'),
alt.Tooltip('Production_Budget'),
alt.Tooltip('Worldwide_Gross'),
alt.Tooltip('US_Gross')
]
).interactive()
<vega.vegalite.VegaLite at 0x118e3c750>

Met dat kleine stukje code kun je al inzoomen op een specifiek gebied—de aswaarden worden automatisch aangepast zodat je je op het interessegebied kunt richten. Maar er zijn nog veel meer geavanceerde interactieve features die je kunt toevoegen. Laten we er één bekijken…
We hebben nu een mooie plot om onze data te tonen. Laten we alle datapunten erbij halen en in de grafiek zetten. Maar wacht, denk je niet dat dat te veel wordt in één visualisatie? Ook willen we ze zeker scheiden op basis van de eerder gemaakte Year-waarde. Hiervoor gebruiken we een geavanceerde selection-eigenschap.
select_year = alt.selection_single(
name='Select', fields=['Year'], init={'Year': 1928},
bind=alt.binding_range(min=1928, max=2046, step=10)
)
alt.Chart(movies_df).mark_point(filled=True).encode(
alt.X('Production_Budget'),
alt.Y('Worldwide_Gross'),
alt.Size('US_Gross'),
alt.Color('Major_Genre'),
alt.OpacityValue(0.7),
tooltip = [alt.Tooltip('Title:N'),
alt.Tooltip('Production_Budget:Q'),
alt.Tooltip('Worldwide_Gross:Q'),
alt.Tooltip('US_Gross:Q')
]
).add_selection(select_year).transform_filter(select_year)
<vega.vegalite.VegaLite at 0x117cd4cd0>

We gebruiken dus de eigenschap add_selection om select_year als een single selection-feature toe te voegen aan de plot en passen daarna transform_filter() toe om de transformatie daadwerkelijk op de plot toe te passen.
Merkte je nog iets nieuws in de code op? De ‘Q’ en ‘N’ in de Tooltip. Dit specificeert het datatype: N-Nominal (categorische data), Q-Quantitative (numerieke data), O-Ordinal (geordende data) of T-Temporal (tijdspunten of intervallen).
Bekijk het oudste en het meest recente jaar in de dataset.
print("The oldest year is: ", movies_df["Year"].min())
print("The latest year is: ", movies_df["Year"].max())
The oldest year is: 1928
The latest year is: 2046
Zoals je ziet zijn er, wanneer je de balk ‘Select_Year’ versleept, niet veel films in de jaren 1928–1967. En er is geen filminformatie vastgelegd na 2018 en zeker niet tot 2046. We kunnen de eigenschap binding_range() gebruiken om het jaartalbereik en de stapgrootte te specificeren.
In een real-life project zijn zulke bevindingen belangrijk en kunnen ze wijzen op fouten in je dataverzameling of ergens in het proces. Je moet effectief met fouten omgaan. Dit is een belangrijke stap tijdens datapreprocessing. Bekijk Data Preparation with pandas voor een introductie tot deze essentiële stappen.
Laten we de jaren aanpassen, en daarmee is onze definitieve visualisatie klaar…
select_year = alt.selection_single(
name='Select', fields=['Year'], init={'Year': 1968},
bind=alt.binding_range(min=1968, max=2008, step=10)
)
alt.Chart(movies_df).mark_point(filled=True).encode(
alt.X('Production_Budget'),
alt.Y('Worldwide_Gross'),
alt.Size('US_Gross'),
alt.Color('Major_Genre'),
alt.OpacityValue(0.7),
tooltip = [alt.Tooltip('Title:N'),
alt.Tooltip('Production_Budget:Q'),
alt.Tooltip('Worldwide_Gross:Q'),
alt.Tooltip('US_Gross:Q')
]
).add_selection(select_year).transform_filter(select_year)
<vega.vegalite.VegaLite at 0x1180cda10>

In deze tutorial maakte je kennis met Altair. Je zag hoe je met een paar regels code prachtige, interactieve grafieken kunt maken die je helpen het verhaal in je data effectiever te vertellen. Deze tutorial wil de kracht en potentie van Altair laten zien. Wil je meer leren over Altair, ga dan naar de officiële website.

