NΓ₯r vi nΓ₯ har brukt litt tid pΓ₯ Γ₯ hente ut og analysere data med DuckDB, er neste steg Γ₯ jobbe visuelt med materialet gjennom visualisering. Det gjΓΈr vi i sΓ₯kalte notebooks β digitale notatbΓΈker som lar oss dokumentere hele arbeidsprosessen med bΓ₯de tekst og kode. Du kan kjΓΈre notebooks lokalt, for eksempel med Jupyter Notebook, men for enkelhetens skyld bruker vi Google Colab β en nettbasert lΓΈsning som sikrer at alle har samme utgangspunkt.
Hva er notebooks?ΒΆ
En notebook er et interaktivt verktΓΈy der du skriver og kjΓΈrer kode direkte i nettleseren. Tenk pΓ₯ det som en blanding av en tekstbehandler og en kode-editor, hvor du kan kombinere forklarende tekst, bilder og kode β alt i Γ©n og samme arbeidsflate. Det er et populΓ¦rt verktΓΈy innen datavitenskap, maskinlΓ¦ring, undervisning β og ikke minst, datajournalistikk.
De viktigste egenskapene:
- KjΓΈring av kode i smΓ₯ deler (celler)): Du kan kjΓΈre koden stykkevis, noe som gjΓΈr det enklere Γ₯ teste, feilsΓΈke og jobbe iterativt.
- Kombinasjon av tekst og kode: Du kan forklare hva du gjΓΈr underveis, noe som gjΓΈr prosessen mer forstΓ₯elig β bΓ₯de for deg selv og andre.
- Visualiseringer: Grafer, kart og diagrammer kan vises direkte i notatboken.
- Dokumentasjon: Hele arbeidsprosessen lagres, slik at du enkelt kan reprodusere resultatene. Perfekt hvis du for eksempel skal sende inn en SKUP-rapport.
I de neste ΓΈvelsene skal vi bruke notebooks, DuckDB, litt enkel Python, grafverktΓΈyet Plotly, og visualiseringsverktΓΈyet Lonboard. Det er flere nye verktΓΈy, men vi holder det pΓ₯ et overkommelig nivΓ₯. Har du ikke programmert fΓΈr, trenger du ikke bekymre deg β mange av kommandoene vil ligne pΓ₯ det du allerede har brukt i DuckDB.
Opprette en notebookΒΆ
Vi starter med Γ₯ opprette en tom notebook i Google Colab:
GΓ₯ til Google Colab.
Velg Fil β Ny notatbok. Du fΓ₯r opp en tom notatbok som ser slik ut:
Figur 1: Tom notebook.
Legg til tekst- og kodecellerΒΆ
En notebook bestΓ₯r av to hovedtyper celler: tekst og kode.
- Tekstceller bruker vi til Γ₯ dokumentere hva vi gjΓΈr og hvorfor.
- Kodeceller bruker vi til Γ₯ skrive og kjΓΈre kommandoer.
Slik gΓ₯r du frem:
Legg til en tekstcelleΒΆ
- Klikk pΓ₯ Tekst-knappen i menylinjen.
Figur 2: Legg til ny tekstlinje.
- Skriv fΓΈlgende:
# Installer nΓΈdevendige bibliotekerLegg til en kodecelleΒΆ
- Klikk pΓ₯ Kode-knappen, og skriv inn:
!pip install lonboard==v0.9.3 duckdb plotly.expressDette installerer Lonboard (versjon 0.9.3), DuckDB og Plotly i notatboken.
- Trykk pΓ₯ play-ikonet til venstre for cellen for Γ₯ kjΓΈre den. Du ser nΓ₯ at Colab laster ned og installerer verktΓΈyene.
Figur 3: FΓΈrste kodecelle installerer avhengigheter.
Last inn DuckDB og nΓΈdvendige modulerΒΆ
- Lag en ny tekstcelle med fΓΈlgende innhold:
# Last inn DuckDB og nΓΈdvendige tilleggsmoduler- Deretter legger du inn fΓΈlgende kode i en ny kodecelle:
import duckdb
con = duckdb.connect()
con.sql('INSTALL spatial;')
con.sql('INSTALL httpfs;')
con.sql('INSTALL h3 FROM community;')
con.sql('LOAD spatial;')
con.sql('LOAD httpfs;')
con.sql('LOAD h3;')Du vil kanskje kjenne igjen noen av kommandoene, selv om syntaksen nΓ₯ er litt annerledes. Kort fortalt er de skrevet i Python og sendes videre til DuckDB-biblioteket for Γ₯ kjΓΈres.
- KjΓΈr cellen med play-knappen. NΓ₯r alt er ferdig, vises et grΓΈnt avhukingssymbol som bekrefter at alt fungerte som det skulle.
Legg inn nΓΈkler til Medieklyngens serverΒΆ
Vi er snart klare til Γ₯ hente data fra Medieklyngens server.
- Start med en ny tekstcelle:
# Legg inn nΓΈkler til serveren- Og sΓ₯ en ny kodecelle med dette innholdet:
con.sql("CREATE SECRET (TYPE R2, KEY_ID '9030e0f90a86af08b08b6e2a1222a778', SECRET '2fe64ae1c22869400f577bb9421602f0f81a83a2f658cea6bdd556f4fc65064b', ACCOUNT_ID 'bca3475a0f4afeb0640daafc17ec2b18');")- Trykk pΓ₯ play. Hvis alt gikk bra, vil du se fΓΈlgende svar fra Colab:
βββββββββββ
β Success β
β boolean β
βββββββββββ€
β true β
βββββββββββGratulerer! Du er nΓ₯ logget pΓ₯ serveren og klar til Γ₯ hente og visualisere data.
Last inn og undersΓΈk dataΒΆ
NΓ₯ skal vi hente inn et datasett fra 20. mars 2025. Start med Γ₯ legge til en ny tekstcelle med fΓΈlgende tittel:
# Last inn data fra 20. mars 2025Deretter legger du inn denne kodecellen:
con.sql("CREATE OR REPLACE TABLE FLIGHTS_20_03_2025 AS SELECT * FROM read_parquet('r2://medieklyngen-radar-data/adsb/history/*/*/*/*.parquet', hive_partitioning = true) WHERE year = 2025 AND month = 03 AND day = 20;")Dette kan ta litt tid. Du ser fremdriften via den horisontale linjen under cellen. NΓ₯r den grΓΈnne avkrysningsboksen vises, er operasjonen fullfΓΈrt og du kan gΓ₯ videre.
Tell antall datapunkterΒΆ
Legg til en ny tekstcelle:
# Tell antall datapunkterOg deretter en kodecelle:
con.sql("SELECT count(*) FROM FLIGHTS_20_03_2025")Du fΓ₯r et svar som dette:
ββββββββββββββββ
β count_star() β
β int64 β
ββββββββββββββββ€
β 4111738 β
ββββββββββββββββOver 4,1 millioner rader β et solid utgangspunkt!
Se pΓ₯ datastrukturenΒΆ
Legg inn en ny tekstcelle:
# Beskriv datastrukturenOg legg deretter inn denne kodecellen:
con.sql("DESCRIBE FLIGHTS_20_03_2025").show(max_width=100)Resultatet ser omtrent slik ut β og mye bΓΈr nΓ₯ vΓ¦re kjent stoff:
βββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ
β column_name β column_type β null β key β default β extra β
β varchar β varchar β varchar β varchar β varchar β varchar β
βββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββ€
β dbFlags β BIGINT β YES β NULL β NULL β NULL β
β desc β VARCHAR β YES β NULL β NULL β NULL β
β icao β VARCHAR β YES β NULL β NULL β NULL β
β ownOp β VARCHAR β YES β NULL β NULL β NULL β
β r β VARCHAR β YES β NULL β NULL β NULL β
β reg_details β STRUCT(description VARCHAR, iso2 VARCHAR, iso3 VARCHAR, natiβ¦ β YES β NULL β NULL β NULL β
β t β VARCHAR β YES β NULL β NULL β NULL β
β timestamp β TIMESTAMP β YES β NULL β NULL β NULL β
β trace β STRUCT(aircraft STRUCT(alert BIGINT, alt_geom BIGINT, baro_rβ¦ β YES β NULL β NULL β NULL β
β year β BIGINT β YES β NULL β NULL β NULL β
β day β VARCHAR β YES β NULL β NULL β NULL β
β month β VARCHAR β YES β NULL β NULL β NULL β
βββββββββββββββ΄βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ€
β 12 rows 6 columns β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββInspiser dataeneΒΆ
Neste steg er Γ₯ ta en nΓ¦rmere titt pΓ₯ selve innholdet i tabellen. Legg fΓΈrst inn en tekstcelle:
# Inspiser dataenecon.sql("SELECT * FROM FLIGHTS_20_03_2025").show(max_width=2500)βββββββββββ¬ββββββββββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ¬ββββββββββ¬ββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ¬ββββββββ¬ββββββββββ¬ββββββββββ
β dbFlags β desc β icao β ownOp β r β reg_details β t β timestamp β trace β year β day β month β
β int64 β varchar β varchar β varchar β varchar β struct(description varchar, iso2 varchar, iso3 varchar, nation varchar) β varchar β timestamp β struct(aircraft struct(alert bigint, alt_geom bigint, baro_rate bigint, category varchar, emergency varchar, flight varchar, geom_rate bigint, gva bigint, ias bigint, mach double, mag_heading double, nac_p bigint, nac_v bigint, nav_altitude_fms bigint, nav_altitude_mcp bigint, nav_heading double, nav_modes varchar[], nav_qnh double, nic bigint, nic_baro bigint, oat varchar, rc bigint, roll double, sda bigint, sil bigint, sil_type varchar, spi bigint, squawk varchar, tas bigint, tat varchar, track double, track_rate double, true_heading double, "type" varchar, "version" bigint, wd bigint, ws bigint), altitude bigint, flags bigint, geometric_altitude bigint, geometric_vertical_rate bigint, ground_speed double, h3_15 varchar, indicated_airspeed bigint, lat double, lon double, on_ground boolean, roll_angle double, source varchar, "timestamp" varchar, track_degrees double, vertical_rate bigint) β int64 β varchar β varchar β
βββββββββββΌββββββββββββββββββΌββββββββββΌββββββββββΌββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββΌββββββββββΌββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββΌββββββββΌββββββββββΌββββββββββ€
β 0 β AIRBUS A-320NEO β 407568 β NULL β G-UZHI β {'description': general, 'iso2': GB, 'iso3': GBR, 'nation': United Kingdom} β A20N β 2025-03-20 00:00:00 β {'aircraft': {'alert': 0, 'alt_geom': 39025, 'baro_rate': 64, 'category': A3, 'emergency': NULL, 'flight': EZY83FE , 'geom_rate': 64, 'gva': 2, 'ias': 240, 'mach': 0.776, 'mag_heading': 101.78, 'nac_p': 9, 'nac_v': 1, 'nav_altitude_fms': NULL, 'nav_altitude_mcp': 39008, 'nav_heading': 0.0, 'nav_modes': NULL, 'nav_qnh': 1013.6, 'nic': 8, 'nic_baro': 1, 'oat': NULL, 'rc': 186, 'roll': NULL, 'sda': 2, 'sil': 3, 'sil_type': perhour, 'spi': 0, 'squawk': 4633, 'tas': NULL, 'tat': NULL, 'track': 104.18, 'track_rate': NULL, 'true_heading': 104.21, 'type': adsb_icao, 'version': 2, 'wd': NULL, 'ws': NULL}, 'altitude': 39025, 'flags': 1, 'geometric_altitude': 39025, 'geometric_vertical_rate': 64, 'ground_speed': 485.8, 'h3_15': 8f1fa6a6ed849b6, 'indicated_airspeed': 240, 'lat': 50.625412, 'lon': 4.749635, 'on_ground': false, 'roll_angle': NULL, 'source': adsb_icao, 'timestamp': 2025-03-20 18:33:30, 'track_degrees': 104.2, 'vertical_rate': 64} β 2025 β 20 β 03 β
β 0 β AIRBUS A-320NEO β 407568 β NULL β G-UZHI β {'description': general, 'iso2': GB, 'iso3': GBR, 'nation': United Kingdom} β A20N β 2025-03-20 00:00:00 β {'aircraft': {'alert': NULL, 'alt_geom': NULL, 'baro_rate': NULL, 'category': NULL, 'emergency': NULL, 'flight': NULL, 'geom_rate': NULL, 'gva': NULL, 'ias': NULL, 'mach': NULL, 'mag_heading': NULL, 'nac_p': NULL, 'nac_v': NULL, 'nav_altitude_fms': NULL, 'nav_altitude_mcp': NULL, 'nav_heading': NULL, 'nav_modes': NULL, 'nav_qnh': NULL, 'nic': NULL, 'nic_baro': NULL, 'oat': NULL, 'rc': NULL, 'roll': NULL, 'sda': NULL, 'sil': NULL, 'sil_type': NULL, 'spi': NULL, 'squawk': NULL, 'tas': NULL, 'tat': NULL, 'track': NULL, 'track_rate': NULL, 'true_heading': NULL, 'type': NULL, 'version': NULL, 'wd': NULL, 'ws': NULL}, 'altitude': 39025, 'flags': 1, 'geometric_altitude': 39025, 'geometric_vertical_rate': -32, 'ground_speed': 486.8, 'h3_15': 8f1fa0d335a6905, 'indicated_airspeed': 239, 'lat': 50.602795, 'lon': 4.889361, 'on_ground': false, 'roll_angle': 0.0, 'source': adsb_icao, 'timestamp': 2025-03-20 18:34:10.800000, 'track_degrees': 104.2, 'vertical_rate': 0} β 2025 β 20 β 03 β
β 0 β AIRBUS A-320NEO β 407568 β NULL β G-UZHI β {'description': general, 'iso2': GB, 'iso3': GBR, 'nation': United Kingdom} β A20N β 2025-03-20 00:00:00 β {'aircraft': {'alert': NULL, 'alt_geom': NULL, 'baro_rate': NULL, 'category': NULL, 'emergency': NULL, 'flight': NULL, 'geom_rate': NULL, 'gva': NULL, 'ias': NULL, 'mach': NULL, 'mag_heading': NULL, 'nac_p': NULL, 'nac_v': NULL, 'nav_altitude_fms': NULL, 'nav_altitude_mcp': NULL, 'nav_heading': NULL, 'nav_modes': NULL, 'nav_qnh': NULL, 'nic': NULL, 'nic_baro': NULL, 'oat': NULL, 'rc': NULL, 'roll': NULL, 'sda': NULL, 'sil': NULL, 'sil_type': NULL, 'spi': NULL, 'squawk': NULL, 'tas': NULL, 'tat': NULL, 'track': NULL, 'track_rate': NULL, 'true_heading': NULL, 'type': NULL, 'version': NULL, 'wd': NULL, 'ws': NULL}, 'altitude': 39025, 'flags': 0, 'geometric_altitude': 39025, 'geometric_vertical_rate': -32, 'ground_speed': 486.8, 'h3_15': 8f1fa0d33436702, 'indicated_airspeed': 239, 'lat': 50.602249, 'lon': 4.892964, 'on_ground': false, 'roll_angle': 0.0, 'source': adsb_icao, 'timestamp': 2025-03-20 18:34:11.900000, 'track_degrees': 104.2, 'vertical_rate': 0} β 2025 β 20 β 03 β
β 0 β AIRBUS A-320NEO β 407568 β NULL β G-UZHI β {'description': general, 'iso2': GB, 'iso3': GBR, 'nation': United Kingdom} β A20N β 2025-03-20 00:00:00 β {'aircraft': {'alert': NULL, 'alt_geom': NULL, 'baro_rate': NULL, 'category': NULL, 'emergency': NULL, 'flight': NULL, 'geom_rate': NULL, 'gva': NULL, 'ias': NULL, 'mach': NULL, 'mag_heading': NULL, 'nac_p': NULL, 'nac_v': NULL, 'nav_altitude_fms': NULL, 'nav_altitude_mcp': NULL, 'nav_heading': NULL, 'nav_modes': NULL, 'nav_qnh': NULL, 'nic': NULL, 'nic_baro': NULL, 'oat': NULL, 'rc': NULL, 'roll': NULL, 'sda': NULL, 'sil': NULL, 'sil_type': NULL, 'spi': NULL, 'squawk': NULL, 'tas': NULL, 'tat': NULL, 'track': NULL, 'track_rate': NULL, 'true_heading': NULL, 'type': NULL, 'version': NULL, 'wd': NULL, 'ws': NULL}, 'altitude': 39025, 'flags': 0, 'geometric_altitude': 39025, 'geometric_vertical_rate': 0, 'ground_speed': 486.8, 'h3_15': 8f1fa0d3341d233, 'indicated_airspeed': 240, 'lat': 50.6017, 'lon': 4.896361, 'on_ground': false, 'roll_angle': -0.3, 'source': adsb_icao, 'timestamp': 2025-03-20 18:34:12.990000, 'track_degrees': 104.2, 'vertical_rate': 0} β 2025 β 20 β 03 β
β 0 β AIRBUS A-320NEO β 407568 β NULL β G-UZHI β {'description': general, 'iso2': GB, 'iso3': GBR, 'nation': United Kingdom} β A20N β 2025-03-20 00:00:00 β {'aircraft': {'alert': 0, 'alt_geom': 39025, 'baro_rate': 0, 'category': A3, 'emergency': NULL, 'flight': EZY83FE , 'geom_rate': 0, 'gva': NULL, 'ias': 240, 'mach': 0.776, 'mag_heading': 102.3, 'nac_p': 9, 'nac_v': 1, 'nav_altitude_fms': NULL, 'nav_altitude_mcp': 39008, 'nav_heading': 0.0, 'nav_modes': NULL, 'nav_qnh': 1013.6, 'nic': 8, 'nic_baro': 1, 'oat': NULL, 'rc': 186, 'roll': -0.18, 'sda': NULL, 'sil': 3, 'sil_type': perhour, 'spi': 0, 'squawk': 4633, 'tas': 436, 'tat': NULL, 'track': 104.15, 'track_rate': -0.03, 'true_heading': 104.77, 'type': adsb_icao, 'version': 2, 'wd': 280, 'ws': 53}, 'altitude': 39025, 'flags': 0, 'geometric_altitude': 39025, 'geometric_vertical_rate': 0, 'ground_speed': 486.8, 'h3_15': 8f1fa0d334e908c, 'indicated_airspeed': 240, 'lat': 50.601119, 'lon': 4.899977, 'on_ground': false, 'roll_angle': -0.2, 'source': adsb_icao, 'timestamp': 2025-03-20 18:34:13.960000, 'track_degrees': 104.2, 'vertical_rate': 0} β 2025 β 20 β 03 β
β 0 β AIRBUS A-320NEO β 407568 β NULL β G-UZHI β {'description': general, 'iso2': GB, 'iso3': GBR, 'nation': United Kingdom} β A20N β 2025-03-20 00:00:00 β {'aircraft': {'alert': NULL, 'alt_geom': NULL, 'baro_rate': NULL, 'category': NULL, 'emergency': NULL, 'flight': NULL, 'geom_rate': NULL, 'gva': NULL, 'ias': NULL, 'mach': NULL, 'mag_heading': NULL, 'nac_p': NULL, 'nac_v': NULL, 'nav_altitude_fms': NULL, 'nav_altitude_mcp': NULL, 'nav_heading': NULL, 'nav_modes': NULL, 'nav_qnh': NULL, 'nic': NULL, 'nic_baro': NULL, 'oat': NULL, 'rc': NULL, 'roll': NULL, 'sda': NULL, 'sil': NULL, 'sil_type': NULL, 'spi': NULL, 'squawk': NULL, 'tas': NULL, 'tat': NULL, 'track': NULL, 'track_rate': NULL, 'true_heading': NULL, 'type': NULL, 'version': NULL, 'wd': NULL, 'ws': NULL}, 'altitude': 39025, 'flags': 0, 'geometric_altitude': 39025, 'geometric_vertical_rate': -32, 'ground_speed': 487.0, 'h3_15': 8f1fa0d15ab275e, 'indicated_airspeed': 240, 'lat': 50.596619, 'lon': 4.927874, 'on_ground': false, 'roll_angle': -0.7, 'source': adsb_icao, 'timestamp': 2025-03-20 18:34:22.160000, 'track_degrees': 104.3, 'vertical_rate': 0} β 2025 β 20 β 03 β
β 0 β AIRBUS A-320NEO β 407568 β NULL β G-UZHI β {'description': general, 'iso2': GB, 'iso3': GBR, 'nation': United Kingdom} β A20N β 2025-03-20 00:00:00 β {'aircraft': {'alert': NULL, 'alt_geom': NULL, 'baro_rate': NULL, 'category': NULL, 'emergency': NULL, 'flight': NULL, 'geom_rate': NULL, 'gva': NULL, 'ias': NULL, 'mach': NULL, 'mag_heading': NULL, 'nac_p': NULL, 'nac_v': NULL, 'nav_altitude_fms': NULL, 'nav_altitude_mcp': NULL, 'nav_heading': NULL, 'nav_modes': NULL, 'nav_qnh': NULL, 'nic': NULL, 'nic_baro': NULL, 'oat': NULL, 'rc': NULL, 'roll': NULL, 'sda': NULL, 'sil': NULL, 'sil_type': NULL, 'spi': NULL, 'squawk': NULL, 'tas': NULL, 'tat': NULL, 'track': NULL, 'track_rate': NULL, 'true_heading': NULL, 'type': NULL, 'version': NULL, 'wd': NULL, 'ws': NULL}, 'altitude': 39025, 'flags': 0, 'geometric_altitude': 39025, 'geometric_vertical_rate': 0, 'ground_speed': 487.0, 'h3_15': 8f1fa0d15376393, 'indicated_airspeed': 240, 'lat': 50.595486, 'lon': 4.93494, 'on_ground': false, 'roll_angle': -0.7, 'source': adsb_icao, 'timestamp': 2025-03-20 18:34:24.120000, 'track_degrees': 104.3, 'vertical_rate': 0} β 2025 β 20 β 03 β
β 0 β AIRBUS A-320NEO β 407568 β NULL β G-UZHI β {'description': general, 'iso2': GB, 'iso3': GBR, 'nation': United Kingdom} β A20N β 2025-03-20 00:00:00 β {'aircraft': {'alert': NULL, 'alt_geom': NULL, 'baro_rate': NULL, 'category': NULL, 'emergency': NULL, 'flight': NULL, 'geom_rate': NULL, 'gva': NULL, 'ias': NULL, 'mach': NULL, 'mag_heading': NULL, 'nac_p': NULL, 'nac_v': NULL, 'nav_altitude_fms': NULL, 'nav_altitude_mcp': NULL, 'nav_heading': NULL, 'nav_modes': NULL, 'nav_qnh': NULL, 'nic': NULL, 'nic_baro': NULL, 'oat': NULL, 'rc': NULL, 'roll': NULL, 'sda': NULL, 'sil': NULL, 'sil_type': NULL, 'spi': NULL, 'squawk': NULL, 'tas': NULL, 'tat': NULL, 'track': NULL, 'track_rate': NULL, 'true_heading': NULL, 'type': NULL, 'version': NULL, 'wd': NULL, 'ws': NULL}, 'altitude': 38975, 'flags': 1, 'geometric_altitude': NULL, 'geometric_vertical_rate': NULL, 'ground_speed': NULL, 'h3_15': 8f1fa01a5d44050, 'indicated_airspeed': NULL, 'lat': 50.511133, 'lon': 5.446918, 'on_ground': false, 'roll_angle': NULL, 'source': adsb_icao, 'timestamp': 2025-03-20 18:36:54.970000, 'track_degrees': NULL, 'vertical_rate': NULL} β 2025 β 20 β 03 β
β 0 β AIRBUS A-320NEO β 407568 β NULL β G-UZHI β {'description': general, 'iso2': GB, 'iso3': GBR, 'nation': United Kingdom} β A20N β 2025-03-20 00:00:00 β {'aircraft': {'alert': 0, 'alt_geom': NULL, 'baro_rate': 256, 'category': A3, 'emergency': NULL, 'flight': NULL, 'geom_rate': 0, 'gva': NULL, 'ias': 238, 'mach': 0.768, 'mag_heading': 102.83, 'nac_p': 8, 'nac_v': NULL, 'nav_altitude_fms': NULL, 'nav_altitude_mcp': 39008, 'nav_heading': 0.0, 'nav_modes': NULL, 'nav_qnh': 1013.6, 'nic': 8, 'nic_baro': 1, 'oat': NULL, 'rc': 186, 'roll': NULL, 'sda': NULL, 'sil': 2, 'sil_type': perhour, 'spi': 0, 'squawk': 4633, 'tas': NULL, 'tat': NULL, 'track': NULL, 'track_rate': NULL, 'true_heading': 105.5, 'type': adsb_icao, 'version': 0, 'wd': NULL, 'ws': NULL}, 'altitude': 39000, 'flags': 0, 'geometric_altitude': NULL, 'geometric_vertical_rate': 0, 'ground_speed': NULL, 'h3_15': 8f1fa01a5122270, 'indicated_airspeed': 238, 'lat': 50.509918, 'lon': 5.454206, 'on_ground': false, 'roll_angle': NULL, 'source': adsb_icao, 'timestamp': 2025-03-20 18:36:57.250000, 'track_degrees': NULL, 'vertical_rate': 256} β 2025 β 20 β 03 β
β 0 β AIRBUS A-320NEO β 407568 β NULL β G-UZHI β {'description': general, 'iso2': GB, 'iso3': GBR, 'nation': United Kingdom} β A20N β 2025-03-20 00:00:00 β {'aircraft': {'alert': NULL, 'alt_geom': NULL, 'baro_rate': NULL, 'category': NULL, 'emergency': NULL, 'flight': NULL, 'geom_rate': NULL, 'gva': NULL, 'ias': NULL, 'mach': NULL, 'mag_heading': NULL, 'nac_p': NULL, 'nac_v': NULL, 'nav_altitude_fms': NULL, 'nav_altitude_mcp': NULL, 'nav_heading': NULL, 'nav_modes': NULL, 'nav_qnh': NULL, 'nic': NULL, 'nic_baro': NULL, 'oat': NULL, 'rc': NULL, 'roll': NULL, 'sda': NULL, 'sil': NULL, 'sil_type': NULL, 'spi': NULL, 'squawk': NULL, 'tas': NULL, 'tat': NULL, 'track': NULL, 'track_rate': NULL, 'true_heading': NULL, 'type': NULL, 'version': NULL, 'wd': NULL, 'ws': NULL}, 'altitude': 39000, 'flags': 0, 'geometric_altitude': NULL, 'geometric_vertical_rate': 0, 'ground_speed': NULL, 'h3_15': 8f1fa01a5154199, 'indicated_airspeed': 238, 'lat': 50.509318, 'lon': 5.457681, 'on_ground': false, 'roll_angle': NULL, 'source': adsb_icao, 'timestamp': 2025-03-20 18:36:58.090000, 'track_degrees': NULL, 'vertical_rate': 256} β 2025 β 20 β 03 β
β Β· β Β· β Β· β Β· β Β· β Β· β Β· β Β· β Β· β Β· β Β· β Β· β
β Β· β Β· β Β· β Β· β Β· β Β· β Β· β Β· β Β· β Β· β Β· β Β· β
β Β· β Β· β Β· β Β· β Β· β Β· β Β· β Β· β Β· β Β· β Β· β Β· β
β 0 β LEARJET 45 β 3cd568 β NULL β D-CICU β {'description': light 5.7 - 14 t MTOW, 'iso2': DE, 'iso3': DEU, 'nation': Germany} β LJ45 β 2025-03-20 00:00:00 β {'aircraft': {'alert': NULL, 'alt_geom': NULL, 'baro_rate': NULL, 'category': NULL, 'emergency': NULL, 'flight': NULL, 'geom_rate': NULL, 'gva': NULL, 'ias': NULL, 'mach': NULL, 'mag_heading': NULL, 'nac_p': NULL, 'nac_v': NULL, 'nav_altitude_fms': NULL, 'nav_altitude_mcp': NULL, 'nav_heading': NULL, 'nav_modes': NULL, 'nav_qnh': NULL, 'nic': NULL, 'nic_baro': NULL, 'oat': NULL, 'rc': NULL, 'roll': NULL, 'sda': NULL, 'sil': NULL, 'sil_type': NULL, 'spi': NULL, 'squawk': NULL, 'tas': NULL, 'tat': NULL, 'track': NULL, 'track_rate': NULL, 'true_heading': NULL, 'type': NULL, 'version': NULL, 'wd': NULL, 'ws': NULL}, 'altitude': 43000, 'flags': 0, 'geometric_altitude': 42475, 'geometric_vertical_rate': NULL, 'ground_speed': 429.8, 'h3_15': 8f1f2472daa542b, 'indicated_airspeed': 218, 'lat': 57.312744, 'lon': 9.889669, 'on_ground': false, 'roll_angle': -1.9, 'source': adsb_icao, 'timestamp': 2025-03-20 09:44:44.780000, 'track_degrees': 187.6, 'vertical_rate': 0} β 2025 β 20 β 03 β
β 0 β LEARJET 45 β 3cd568 β NULL β D-CICU β {'description': light 5.7 - 14 t MTOW, 'iso2': DE, 'iso3': DEU, 'nation': Germany} β LJ45 β 2025-03-20 00:00:00 β {'aircraft': {'alert': NULL, 'alt_geom': NULL, 'baro_rate': NULL, 'category': NULL, 'emergency': NULL, 'flight': NULL, 'geom_rate': NULL, 'gva': NULL, 'ias': NULL, 'mach': NULL, 'mag_heading': NULL, 'nac_p': NULL, 'nac_v': NULL, 'nav_altitude_fms': NULL, 'nav_altitude_mcp': NULL, 'nav_heading': NULL, 'nav_modes': NULL, 'nav_qnh': NULL, 'nic': NULL, 'nic_baro': NULL, 'oat': NULL, 'rc': NULL, 'roll': NULL, 'sda': NULL, 'sil': NULL, 'sil_type': NULL, 'spi': NULL, 'squawk': NULL, 'tas': NULL, 'tat': NULL, 'track': NULL, 'track_rate': NULL, 'true_heading': NULL, 'type': NULL, 'version': NULL, 'wd': NULL, 'ws': NULL}, 'altitude': 43000, 'flags': 0, 'geometric_altitude': 42475, 'geometric_vertical_rate': NULL, 'ground_speed': 429.8, 'h3_15': 8f1f2472da86b9b, 'indicated_airspeed': 218, 'lat': 57.311577, 'lon': 9.889379, 'on_ground': false, 'roll_angle': -1.9, 'source': adsb_icao, 'timestamp': 2025-03-20 09:44:45.330000, 'track_degrees': 187.6, 'vertical_rate': 64} β 2025 β 20 β 03 β
β 0 β LEARJET 45 β 3cd568 β NULL β D-CICU β {'description': light 5.7 - 14 t MTOW, 'iso2': DE, 'iso3': DEU, 'nation': Germany} β LJ45 β 2025-03-20 00:00:00 β {'aircraft': {'alert': NULL, 'alt_geom': NULL, 'baro_rate': NULL, 'category': NULL, 'emergency': NULL, 'flight': NULL, 'geom_rate': NULL, 'gva': NULL, 'ias': NULL, 'mach': NULL, 'mag_heading': NULL, 'nac_p': NULL, 'nac_v': NULL, 'nav_altitude_fms': NULL, 'nav_altitude_mcp': NULL, 'nav_heading': NULL, 'nav_modes': NULL, 'nav_qnh': NULL, 'nic': NULL, 'nic_baro': NULL, 'oat': NULL, 'rc': NULL, 'roll': NULL, 'sda': NULL, 'sil': NULL, 'sil_type': NULL, 'spi': NULL, 'squawk': NULL, 'tas': NULL, 'tat': NULL, 'track': NULL, 'track_rate': NULL, 'true_heading': NULL, 'type': NULL, 'version': NULL, 'wd': NULL, 'ws': NULL}, 'altitude': 43000, 'flags': 0, 'geometric_altitude': 42475, 'geometric_vertical_rate': NULL, 'ground_speed': 429.7, 'h3_15': 8f1f2472d068980, 'indicated_airspeed': 218, 'lat': 57.309994, 'lon': 9.888936, 'on_ground': false, 'roll_angle': -1.9, 'source': adsb_icao, 'timestamp': 2025-03-20 09:44:46.210000, 'track_degrees': 187.5, 'vertical_rate': 0} β 2025 β 20 β 03 β
β 0 β LEARJET 45 β 3cd568 β NULL β D-CICU β {'description': light 5.7 - 14 t MTOW, 'iso2': DE, 'iso3': DEU, 'nation': Germany} β LJ45 β 2025-03-20 00:00:00 β {'aircraft': {'alert': 0, 'alt_geom': 42475, 'baro_rate': 0, 'category': A2, 'emergency': none, 'flight': UNI132 , 'geom_rate': NULL, 'gva': 2, 'ias': 218, 'mach': 0.772, 'mag_heading': 187.73, 'nac_p': 10, 'nac_v': 1, 'nav_altitude_fms': NULL, 'nav_altitude_mcp': 43008, 'nav_heading': NULL, 'nav_modes': NULL, 'nav_qnh': 1013.6, 'nic': 8, 'nic_baro': 1, 'oat': NULL, 'rc': 186, 'roll': -2.11, 'sda': 2, 'sil': 3, 'sil_type': perhour, 'spi': 0, 'squawk': 7670, 'tas': 444, 'tat': NULL, 'track': 187.49, 'track_rate': -0.03, 'true_heading': 191.95, 'type': adsb_icao, 'version': 2, 'wd': 257, 'ws': 37}, 'altitude': 43000, 'flags': 0, 'geometric_altitude': 42475, 'geometric_vertical_rate': NULL, 'ground_speed': 429.7, 'h3_15': 8f1f2472d05b9a1, 'indicated_airspeed': 218, 'lat': 57.308029, 'lon': 9.888468, 'on_ground': false, 'roll_angle': -2.1, 'source': adsb_icao, 'timestamp': 2025-03-20 09:44:47.140000, 'track_degrees': 187.5, 'vertical_rate': 0} β 2025 β 20 β 03 β
β 0 β LEARJET 45 β 3cd568 β NULL β D-CICU β {'description': light 5.7 - 14 t MTOW, 'iso2': DE, 'iso3': DEU, 'nation': Germany} β LJ45 β 2025-03-20 00:00:00 β {'aircraft': {'alert': NULL, 'alt_geom': NULL, 'baro_rate': NULL, 'category': NULL, 'emergency': NULL, 'flight': NULL, 'geom_rate': NULL, 'gva': NULL, 'ias': NULL, 'mach': NULL, 'mag_heading': NULL, 'nac_p': NULL, 'nac_v': NULL, 'nav_altitude_fms': NULL, 'nav_altitude_mcp': NULL, 'nav_heading': NULL, 'nav_modes': NULL, 'nav_qnh': NULL, 'nic': NULL, 'nic_baro': NULL, 'oat': NULL, 'rc': NULL, 'roll': NULL, 'sda': NULL, 'sil': NULL, 'sil_type': NULL, 'spi': NULL, 'squawk': NULL, 'tas': NULL, 'tat': NULL, 'track': NULL, 'track_rate': NULL, 'true_heading': NULL, 'type': NULL, 'version': NULL, 'wd': NULL, 'ws': NULL}, 'altitude': 43000, 'flags': 0, 'geometric_altitude': 42475, 'geometric_vertical_rate': NULL, 'ground_speed': 429.7, 'h3_15': 8f1f2472d765830, 'indicated_airspeed': 218, 'lat': 57.306038, 'lon': 9.88805, 'on_ground': false, 'roll_angle': -1.8, 'source': adsb_icao, 'timestamp': 2025-03-20 09:44:48.270000, 'track_degrees': 187.5, 'vertical_rate': 0} β 2025 β 20 β 03 β
β 0 β LEARJET 45 β 3cd568 β NULL β D-CICU β {'description': light 5.7 - 14 t MTOW, 'iso2': DE, 'iso3': DEU, 'nation': Germany} β LJ45 β 2025-03-20 00:00:00 β {'aircraft': {'alert': NULL, 'alt_geom': NULL, 'baro_rate': NULL, 'category': NULL, 'emergency': NULL, 'flight': NULL, 'geom_rate': NULL, 'gva': NULL, 'ias': NULL, 'mach': NULL, 'mag_heading': NULL, 'nac_p': NULL, 'nac_v': NULL, 'nav_altitude_fms': NULL, 'nav_altitude_mcp': NULL, 'nav_heading': NULL, 'nav_modes': NULL, 'nav_qnh': NULL, 'nic': NULL, 'nic_baro': NULL, 'oat': NULL, 'rc': NULL, 'roll': NULL, 'sda': NULL, 'sil': NULL, 'sil_type': NULL, 'spi': NULL, 'squawk': NULL, 'tas': NULL, 'tat': NULL, 'track': NULL, 'track_rate': NULL, 'true_heading': NULL, 'type': NULL, 'version': NULL, 'wd': NULL, 'ws': NULL}, 'altitude': 43000, 'flags': 0, 'geometric_altitude': 42475, 'geometric_vertical_rate': NULL, 'ground_speed': 429.7, 'h3_15': 8f1f2472d7460d6, 'indicated_airspeed': 218, 'lat': 57.304501, 'lon': 9.887607, 'on_ground': false, 'roll_angle': -1.8, 'source': adsb_icao, 'timestamp': 2025-03-20 09:44:49.100000, 'track_degrees': 187.5, 'vertical_rate': 0} β 2025 β 20 β 03 β
β 0 β LEARJET 45 β 3cd568 β NULL β D-CICU β {'description': light 5.7 - 14 t MTOW, 'iso2': DE, 'iso3': DEU, 'nation': Germany} β LJ45 β 2025-03-20 00:00:00 β {'aircraft': {'alert': NULL, 'alt_geom': NULL, 'baro_rate': NULL, 'category': NULL, 'emergency': NULL, 'flight': NULL, 'geom_rate': NULL, 'gva': NULL, 'ias': NULL, 'mach': NULL, 'mag_heading': NULL, 'nac_p': NULL, 'nac_v': NULL, 'nav_altitude_fms': NULL, 'nav_altitude_mcp': NULL, 'nav_heading': NULL, 'nav_modes': NULL, 'nav_qnh': NULL, 'nic': NULL, 'nic_baro': NULL, 'oat': NULL, 'rc': NULL, 'roll': NULL, 'sda': NULL, 'sil': NULL, 'sil_type': NULL, 'spi': NULL, 'squawk': NULL, 'tas': NULL, 'tat': NULL, 'track': NULL, 'track_rate': NULL, 'true_heading': NULL, 'type': NULL, 'version': NULL, 'wd': NULL, 'ws': NULL}, 'altitude': 43000, 'flags': 0, 'geometric_altitude': 42475, 'geometric_vertical_rate': NULL, 'ground_speed': 430.7, 'h3_15': 8f1f2472d60e923, 'indicated_airspeed': 217, 'lat': 57.302127, 'lon': 9.887075, 'on_ground': false, 'roll_angle': -1.9, 'source': adsb_icao, 'timestamp': 2025-03-20 09:44:50.250000, 'track_degrees': 187.5, 'vertical_rate': 0} β 2025 β 20 β 03 β
β 0 β LEARJET 45 β 3cd568 β NULL β D-CICU β {'description': light 5.7 - 14 t MTOW, 'iso2': DE, 'iso3': DEU, 'nation': Germany} β LJ45 β 2025-03-20 00:00:00 β {'aircraft': {'alert': 0, 'alt_geom': 42475, 'baro_rate': 0, 'category': A2, 'emergency': none, 'flight': UNI132 , 'geom_rate': NULL, 'gva': 2, 'ias': 217, 'mach': 0.772, 'mag_heading': 187.73, 'nac_p': 10, 'nac_v': 1, 'nav_altitude_fms': NULL, 'nav_altitude_mcp': 43008, 'nav_heading': NULL, 'nav_modes': NULL, 'nav_qnh': 1013.6, 'nic': 8, 'nic_baro': 1, 'oat': NULL, 'rc': 186, 'roll': -1.93, 'sda': 2, 'sil': 3, 'sil_type': perhour, 'spi': 0, 'squawk': 7670, 'tas': 442, 'tat': NULL, 'track': 187.47, 'track_rate': -0.03, 'true_heading': 191.95, 'type': adsb_icao, 'version': 2, 'wd': 261, 'ws': 36}, 'altitude': 43000, 'flags': 0, 'geometric_altitude': 42475, 'geometric_vertical_rate': NULL, 'ground_speed': 430.7, 'h3_15': 8f1f2472d68986a, 'indicated_airspeed': 217, 'lat': 57.299753, 'lon': 9.886455, 'on_ground': false, 'roll_angle': -1.9, 'source': adsb_icao, 'timestamp': 2025-03-20 09:44:51.220000, 'track_degrees': 187.5, 'vertical_rate': 0} β 2025 β 20 β 03 β
β 0 β LEARJET 45 β 3cd568 β NULL β D-CICU β {'description': light 5.7 - 14 t MTOW, 'iso2': DE, 'iso3': DEU, 'nation': Germany} β LJ45 β 2025-03-20 00:00:00 β {'aircraft': {'alert': NULL, 'alt_geom': NULL, 'baro_rate': NULL, 'category': NULL, 'emergency': NULL, 'flight': NULL, 'geom_rate': NULL, 'gva': NULL, 'ias': NULL, 'mach': NULL, 'mag_heading': NULL, 'nac_p': NULL, 'nac_v': NULL, 'nav_altitude_fms': NULL, 'nav_altitude_mcp': NULL, 'nav_heading': NULL, 'nav_modes': NULL, 'nav_qnh': NULL, 'nic': NULL, 'nic_baro': NULL, 'oat': NULL, 'rc': NULL, 'roll': NULL, 'sda': NULL, 'sil': NULL, 'sil_type': NULL, 'spi': NULL, 'squawk': NULL, 'tas': NULL, 'tat': NULL, 'track': NULL, 'track_rate': NULL, 'true_heading': NULL, 'type': NULL, 'version': NULL, 'wd': NULL, 'ws': NULL}, 'altitude': 43000, 'flags': 0, 'geometric_altitude': 42475, 'geometric_vertical_rate': NULL, 'ground_speed': 430.7, 'h3_15': 8f1f24729d0686e, 'indicated_airspeed': 217, 'lat': 57.297775, 'lon': 9.885979, 'on_ground': false, 'roll_angle': -1.9, 'source': adsb_icao, 'timestamp': 2025-03-20 09:44:52.380000, 'track_degrees': 187.5, 'vertical_rate': 0} β 2025 β 20 β 03 β
β 0 β LEARJET 45 β 3cd568 β NULL β D-CICU β {'description': light 5.7 - 14 t MTOW, 'iso2': DE, 'iso3': DEU, 'nation': Germany} β LJ45 β 2025-03-20 00:00:00 β {'aircraft': {'alert': NULL, 'alt_geom': NULL, 'baro_rate': NULL, 'category': NULL, 'emergency': NULL, 'flight': NULL, 'geom_rate': NULL, 'gva': NULL, 'ias': NULL, 'mach': NULL, 'mag_heading': NULL, 'nac_p': NULL, 'nac_v': NULL, 'nav_altitude_fms': NULL, 'nav_altitude_mcp': NULL, 'nav_heading': NULL, 'nav_modes': NULL, 'nav_qnh': NULL, 'nic': NULL, 'nic_baro': NULL, 'oat': NULL, 'rc': NULL, 'roll': NULL, 'sda': NULL, 'sil': NULL, 'sil_type': NULL, 'spi': NULL, 'squawk': NULL, 'tas': NULL, 'tat': NULL, 'track': NULL, 'track_rate': NULL, 'true_heading': NULL, 'type': NULL, 'version': NULL, 'wd': NULL, 'ws': NULL}, 'altitude': 43000, 'flags': 0, 'geometric_altitude': 42475, 'geometric_vertical_rate': NULL, 'ground_speed': 430.7, 'h3_15': 8f1f24729da84ab, 'indicated_airspeed': 218, 'lat': 57.295843, 'lon': 9.885569, 'on_ground': false, 'roll_angle': -1.4, 'source': adsb_icao, 'timestamp': 2025-03-20 09:44:53.410000, 'track_degrees': 187.5, 'vertical_rate': -64} β 2025 β 20 β 03 β
βββββββββββ΄ββββββββββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ΄ββββββββββ΄ββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ΄ββββββββ΄ββββββββββ΄ββββββββββ€
β ? rows (>9999 rows, 20 shown) 12 columns β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Antall fly per landΒΆ
La oss gjΓΈre en ΓΈvelse vi ogsΓ₯ har gjort tidligere i DuckDB: Vi teller antall fly per land.
Start med Γ₯ legge inn fΓΈlgende tekstcelle:
# Tell antall fly per landsql = """
SELECT reg_details.nation as land,
COUNT(DISTINCT r) AS fly
FROM FLIGHTS_20_03_2025
WHERE LENGTH(reg_details.nation)
GROUP BY 1
ORDER BY 2 DESC
"""
con.sql(sql).show(max_rows=30)
Denne spΓΈrringen gir oss en oversikt over hvor mange ulike fly som er registrert i hvert land den dagen. Utvalget vises med maksimum 30 rader:
ββββββββββββββββββββββββ¬ββββββββ
β land β fly β
β varchar β int64 β
ββββββββββββββββββββββββΌββββββββ€
β Germany β 244 β
β United Kingdom β 237 β
β Netherlands β 227 β
β Ireland β 152 β
β Norway β 147 β
β Malta β 113 β
β Sweden β 106 β
β United States β 100 β
β Turkey β 96 β
β Austria β 74 β
β Poland β 64 β
β France β 62 β
β United Arab Emirates β 56 β
β Spain β 55 β
β China β 51 β
β Β· β Β· β
β Β· β Β· β
β Β· β Β· β
β Australia β 3 β
β Guernsey β 3 β
β Isle of Man β 2 β
β Taiwan β 2 β
β Bahrain β 2 β
β Georgia β 2 β
β Bangladesh β 2 β
β Kuwait β 2 β
β Sri Lanka β 1 β
β Uzbekistan β 1 β
β Kenya β 1 β
β Belarus β 1 β
β Pakistan β 1 β
β Azerbaijan β 1 β
β Oman β 1 β
ββββββββββββββββββββββββ΄ββββββββ€
β 65 rows (30 shown) β
ββββββββββββββββββββββββββββββββResultatet er kjent, men mΓ₯ten vi kjΓΈrer spΓΈrringen pΓ₯ er litt ny. Vi starter med sql = """, og legger inn SQL-spΓΈrringen som en tekstblokk. PΓ₯ den mΓ₯ten oppretter vi en variabel som inneholder spΓΈrringen β noe som gjΓΈr det enkelt Γ₯ gjenbruke den senere, om vi ΓΈnsker. Her kjΓΈrer vi den bare Γ©n gang, ved Γ₯ sende variabelen inn i DuckDB-forbindelsen vΓ₯r med con.sql(sql). Vi ber samtidig om Γ₯ vise maksimalt 30 rader med show(max_rows=30).
Kanskje du, som meg, tenker at det minner litt vel mye om det vi gjorde direkte i DuckDB. Helt enig! NΓ₯ er det pΓ₯ tide Γ₯ ta visualiseringen ett hakk videre.
Visualiser fly per land i penere tabellΒΆ
Vi starter enkelt, med Γ₯ konvertere dataene til et format som er mer egnet for moderne nettleservisning. Dette gjΓΈr vi ved hjelp av Polars β et raskt og fleksibelt Python-verktΓΈy for databehandling.
# Visualiser fly per land i penere tabellimport polars as pl
pl.Config(set_tbl_rows=100)
flyperland = con.sql(sql).pl()
flyperland| land | fly |
|---|---|
| βGermanyβ | 244 |
| βUnited Kingdomβ | 237 |
| βNetherlandsβ | 227 |
| βIrelandβ | 152 |
| βNorwayβ | 147 |
| βMaltaβ | 113 |
| βSwedenβ | 106 |
| βUnited Statesβ | 100 |
| βTurkeyβ | 96 |
| βAustriaβ | 74 |
| βPolandβ | 64 |
| βFranceβ | 62 |
| βUnited Arab Emiratesβ | 56 |
| βSpainβ | 55 |
| βChinaβ | 51 |
| βFinlandβ | 45 |
| βDenmarkβ | 44 |
| βPortugalβ | 43 |
| βQatarβ | 37 |
| βBelgiumβ | 34 |
| βHungaryβ | 30 |
| βRussiaβ | 23 |
| βLatviaβ | 22 |
| βLiechtensteinβ | 18 |
| βCanadaβ | 15 |
| βIndiaβ | 14 |
| βIcelandβ | 13 |
| βSingaporeβ | 11 |
| βGreeceβ | 12 |
| βEgyptβ | 9 |
| βJapanβ | 9 |
| βSaudi Arabiaβ | 8 |
| βIsraelβ | 7 |
| βBulgariaβ | 7 |
| βCzech Republicβ | 6 |
| βSan Marinoβ | 6 |
| βSerbiaβ | 6 |
| βCroatiaβ | 6 |
| βRomaniaβ | 6 |
| βJordanβ | 5 |
| βSlovakiaβ | 5 |
| βItalyβ | 5 |
| βEthiopiaβ | 5 |
| βEstoniaβ | 4 |
| βThailandβ | 4 |
| βUkraineβ | 4 |
| βSouth Koreaβ | 4 |
| βAustraliaβ | 3 |
| βZimbabweβ | 3 |
| βMoroccoβ | 3 |
| βMalaysiaβ | 3 |
| βGuernseyβ | 3 |
| βGeorgiaβ | 2 |
| βTaiwanβ | 2 |
| βBahrainβ | 2 |
| βIsle of Manβ | 2 |
| βKuwaitβ | 2 |
| βBangladeshβ | 2 |
| βOmanβ | 1 |
| βAzerbaijanβ | 1 |
| βPakistanβ | 1 |
| βBelarusβ | 1 |
| βSri Lankaβ | 1 |
| βKenyaβ | 1 |
| βUzbekistanβ | 1 |
Her skjer det tre ting:
Vi importerer Polars.
Vi setter opp konfigurasjonen slik at tabellen kan vise opptil 100 rader.
Vi bruker
.pl()til Γ₯ hente resultatet fra DuckDB-spΓΈrringen som en Polars-tabell, og viser den ved Γ₯ referere til variabelenflyperland.
Resultatet er en langt mer leservennlig tabell enn den rΓ₯ tekstutskriften fra DuckDB. Du fΓ₯r oversikt over alle land, sortert etter antall fly β og du kan enkelt bruke dataene videre til grafer, kart og annen visualisering.
Lagre tabellen til CSVΒΆ
En av fordelene med Polars er hvor enkelt det er Γ₯ eksportere data til ulike formater. NΓ₯r du har hentet ut et datasett du vil ta vare pΓ₯ eller bruke videre, er det for eksempel veldig lett Γ₯ lagre det som en CSV-fil:
Legg til en tekstcelle:
# Lagre til CSVOg deretter denne kodecellen:
flyperland.write_csv("flyperland.csv")Hvor finner jeg filen?ΒΆ
Et godt spΓΈrsmΓ₯l! Til venstre i Google Colab-vinduet finner du en vertikal meny. Klikk pΓ₯ mappesymbolet nederst for Γ₯ Γ₯pne filvisningen. Om du ikke ser filen med en gang, kan du klikke pΓ₯ last inn pΓ₯ nytt-knappen (de to sirklene som danner en pil) for Γ₯ oppdatere visningen.
Figur 4: Filoversikten i Google Colab β klikk pΓ₯ mappen nederst, og last inn pΓ₯ nytt om nΓΈdvendig.
StolpediagramΒΆ
Nok tall og tabeller β nΓ₯ er det pΓ₯ tide med litt visuell magi! Og da passer det perfekt Γ₯ introdusere et nytt verktΓΈy pΓ₯ scenen: Plotly. Dette visualiseringsbiblioteket lar deg lage stilrene og interaktive grafer med minimale mengder kode.
La oss starte med Γ₯ lage et stolpediagram over fly per land:
# Visualiser som stolpediagramimport plotly.express as px
stolpe = px.bar(flyperland, x='land', y='fly', title="Fly per land")
stolpe
Figur 5: Fly per land visualisert som stolpediagram.
SΓ₯ enkelt β og sΓ₯ fint! Diagrammet er interaktivt, og du kan blant annet:
- Hovre med musepekeren i ΓΈvre bildekant for Γ₯ fΓ₯ opp en meny.
- Zoome inn og ut.
- Trykke pΓ₯ kamerasymbolet for Γ₯ laste ned grafen som PNG.
Vil du lagre hele grafen med all interaktiviteten intakt? Plotly har tenkt pΓ₯ det ogsΓ₯. Du kan enkelt lagre visualiseringen som en HTML-fil:
# Lagre til HTMLstolpe.write_html("stolpe.html")Filen dukker opp i den samme filutforskeren som vi brukte da vi lagret CSV. Klikk pΓ₯ mappesymbolet til venstre, og husk Γ₯ trykke last inn pΓ₯ nytt hvis du ikke ser filen med Γ©n gang.
KakediagramΒΆ
Siden flyobservasjonene vΓ₯re utgjΓΈr en absolutt mengde, egner de seg ogsΓ₯ godt for visualisering som kakediagram. Det krever bare en liten endring fra stolpediagrammet, og vips β dataene blir til kake:
# Visualiser som kakediagramkake = px.pie(flyperland, names='land', values='fly', title="Fly per land")
kake
Figur 6: Fly per land visualisert som (et litt sprengt) kakediagram.
Tada! Kakediagram, rett ut av ovnen. Men β dette ser kanskje litt sprengt ut?
NΓ₯r vi presser inn over 60 land med ulikt antall fly i Γ©n og samme sirkel, blir resultatet bΓ₯de visuelt rotete og vanskelig Γ₯ lese. Mange land har bare noen fΓ₯ fly, og det gir lite mening Γ₯ gi dem hver sin tynne kakebit.
Begrens detaljnivΓ₯et β grupper smΓ₯ landΒΆ
LΓΈsningen? Vi samler alle land med fΓ¦rre enn 100 observerte fly i en felles gruppe: Other countries. Det gjΓΈr vi ved Γ₯ legge inn litt enkel logikk i SQL-spΓΈrringen:
# Kakediagram - grupper smΓ₯ landsql = """
WITH flight_counts AS (
SELECT
reg_details.nation as land,
COUNT(DISTINCT r) AS fly
FROM
FLIGHTS_20_03_2025
WHERE
LENGTH(reg_details.nation) > 0
GROUP BY
reg_details.nation
)
SELECT
CASE
WHEN fly < 100 THEN 'Other countries'
ELSE land
END AS land,
CAST(SUM(fly) AS BIGINT) AS fly
FROM
flight_counts
GROUP BY
1
ORDER BY
2 DESC;
"""
flyperland = con.sql(sql).pl()
kake = px.pie(flyperland, names='land', values='fly', title="Fly per land")
kakeHer har vi bakt litt enkel programmeringslogikk inn i spΓΈrringen. Kort fortalt finner vi land som har under 100 observerte fly den aktuelle tidsperioden, og legger disse til i landet Other countries. Da ser vi umiddelbart at kakediagrammet bΓ₯de blir penere og mer lesbart.
Figur 7: Fly per land visualisert som (et litt penere) kakediagram.
Ved hjelp av CASE WHEN-logikken over slΓ₯r vi sammen alle smΓ₯nasjonene i Γ©n kategori. Resultatet? Et diagram som bΓ₯de ser bedre ut og er langt lettere Γ₯ lese.
WiderΓΈe-flyet som nΓΈdlandet i BergenΒΆ
Tirsdag 11. mars nΓΈdlandet et WiderΓΈe-fly i Bergen. Hendelsen var heldigvis udramatisk, men siden den skjedde like fΓΈr vΓ₯r andre kursΓΈkt, passet det godt Γ₯ bruke den som et ekte case. NΓ₯ skal vi jobbe oss gjennom hvordan man kan hente ut, analysere og visualisere flydata knyttet til en slik hendelse β pΓ₯ mΓ₯ter som kunne vΓ¦rt relevante i lokal nyhetsdekning.
- Vi starter med Γ₯ hente ut alle flydata for 11. mars 2025:
# Hent ut alle data fra 11. mars 2025sql = """
CREATE TABLE flights_11_03_25 AS
SELECT * FROM read_parquet('r2://medieklyngen-radar-data/adsb/history/*/*/*/*.parquet', hive_partitioning = true)
WHERE year = 2025 AND month = 03 AND day = 11;
"""
con.sql(sql)- Deretter filtrer vi datasettet pΓ₯ flyet LN-WDP i aktuell tidsperiode:
# Filtrer pΓ₯ LN-WDP i aktuell tidsperiodesql = """
SELECT r, trace.lon, trace.lat, trace.altitude, trace.ground_speed, trace.timestamp
FROM flights_11_03_25
WHERE r LIKE 'LN-WDP' AND trace.timestamp > '2025-03-11 07:00:23.710000' AND trace.timestamp < '2025-03-11 10:00:23.710000' AND trace.lat IS NOT NULL and trace.lon IS NOT NULL
ORDER BY trace.timestamp;
"""
nodlanding = con.sql(sql).pl()
pl.Config(set_tbl_rows=10)
nodlanding| r | lon | lat | altitude | ground_speed | timestamp |
|---|---|---|---|---|---|
| βLN-WDPβ | 5.22336 | 60.287464 | null | 20.5 | β2025-03-11 07:29:53.870000β |
| βLN-WDPβ | 5.223454 | 60.287189 | null | 19.5 | β2025-03-11 07:29:56.830000β |
| βLN-WDPβ | 5.223631 | 60.286649 | null | 16.5 | β2025-03-11 07:30:03.480000β |
| βLN-WDPβ | 5.223857 | 60.285976 | null | 16.5 | β2025-03-11 07:30:12.620000β |
| βLN-WDPβ | 5.223852 | 60.285939 | null | 16.5 | β2025-03-11 07:30:13.160000β |
| β¦ | β¦ | β¦ | β¦ | β¦ | β¦ |
| βLN-WDPβ | 5.221915 | 60.282074 | 500 | 124.6 | β2025-03-11 08:20:59.770000β |
| βLN-WDPβ | 5.221726 | 60.282623 | 475 | 124.6 | β2025-03-11 08:21:00.850000β |
| βLN-WDPβ | 5.221347 | 60.283768 | 450 | 124.5 | β2025-03-11 08:21:02.720000β |
| βLN-WDPβ | 5.221252 | 60.284077 | 450 | 124.5 | β2025-03-11 08:21:03.480000β |
| βLN-WDPβ | 5.221154 | 60.28445 | 450 | 124.5 | β2025-03-11 08:21:03.910000β |
Resultatet viser alle datapunktene vi har om denne flyvningen, filtrert pΓ₯ kjennetegn (r) og tidsintervall. Ved Γ₯ bruke pl.Config(set_tbl_rows=10) fΓ₯r vi automatisk vist de fΓΈrste og siste 5 radene i tabellen β en praktisk mΓ₯te Γ₯ fΓ₯ et raskt inntrykk av datasettet pΓ₯.
HΓΈyde og fart over tidΒΆ
La oss se nΓ¦rmere pΓ₯ hvordan flyet beveget seg gjennom luftrommet, bΓ₯de i hΓΈyde og fart:
# Flyets hΓΈyde over tidlinje = px.line(nodlanding, x='timestamp', y='altitude', title="Flyets hΓΈyde over tid")
linje
Figur 8: Flyets hΓΈyde over tid.
# Flyets fart over tidlinje = px.line(nodlanding, x='timestamp', y='ground_speed', title="Flyets fart over tid")
linje
Figur 9: Flyets fart over tid.
Enkelt, oversiktlig og nyttig. Her fΓ₯r vi raskt et bilde av flyets bevegelser og endringer underveis. Og som vi ser β til tross for nΓΈdlandingen, ser dataene ganske udramatiske ut, akkurat som rapportert.
Visualisering pΓ₯ kartΒΆ
Grafene gir oss innsikt, men i hendelsesjournalistikk er det ofte kartet som virkelig skaper forstΓ₯else. Heldigvis kan vi enkelt plassere flyets rute direkte pΓ₯ et interaktivt kart med Plotly:
# Plott WiderΓΈe-flighten pΓ₯ et kartkart = px.line_map(nodlanding, lat='lat', lon='lon', hover_data=['timestamp', 'altitude', 'ground_speed'])
kart.update_layout(height=540, width=960, map_zoom=6, map_center_lat = 59.5, map_center_lon = 6)
kart
Figur 10: WiderΓΈe-flyets rute plottet pΓ₯ kart.
Og der har vi det! Flyets ferd fra Bergen, via Rogaland β og tilbake til Bergen.
Selv om det krever litt mer kode enn de tidligere grafene, er det fortsatt overkommelig. Her bruker vi line_map for Γ₯ tegne ruten basert pΓ₯ geografiske koordinater. Ved Γ₯ legge til hover_data fΓ₯r vi i tillegg opp info om tidspunkt, hΓΈyde og fart nΓ₯r vi beveger musepekeren over ruten.
NΓ₯r du er fornΓΈyd med visualiseringen, kan du eksportere kartet som en PNG eller lagre det som HTML med full interaktivitet β perfekt for bruk i en nyhetsartikkel pΓ₯ nett.
Heatmaps med LonboardΒΆ
Vi var sΓ₯ vidt innom heatmaps da vi jobbet med sanntidsdata tidligere i kurset. Som du kanskje husker, er dette en utmerket mΓ₯te Γ₯ kartlegge flyaktivitet pΓ₯: Hvor er det mest trafikk, og hvordan fordeler bevegelsene seg i rom og tid?
Visualisering av slike mΓΈnstre krever ofte store datamengder β og da kommer Lonboard til sin rett. VerktΓΈyet er spesiallaget for Γ₯ hΓ₯ndtere store geografiske datasett, og genererer heatmaps pΓ₯ en bΓ₯de rask og imponerende mΓ₯te.
La oss bruke Lonboard til Γ₯ lage et heatmap av all tilgjengelig flytrafikk lΓΈrdag 8. mars 2025.
- Last inn data fra 8. mars:
# Last inn data fra 8. marssql = """
CREATE TABLE flights_08_03_2025 AS
SELECT * FROM read_parquet('r2://medieklyngen-radar-data/adsb/history/*/*/*/*.parquet', hive_partitioning = true)
WHERE year = 2025 AND month = 03 AND day = 08;
"""
con.sql(sql)- GjΓΈr dataene klare for Lonboard. Vi lager en spΓΈrring som henter ut tidspunkt, posisjon og registreringsnummer, og gjΓΈr posisjonen om til et geometriobjekt (
ST_POINT):
sql = """
SELECT trace.timestamp as Time, ST_POINT(trace.lon, trace.lat) as geom, r as Reg from flights_08_03_2025
GROUP BY ALL;
"""
query = con.sql(sql)- NΓ₯ er alt klart! Vi bruker Lonboards HeatmapLayer og tegner det pΓ₯ et interaktivt kart:
from lonboard import Map, HeatmapLayer, PathLayer
layer = HeatmapLayer.from_duckdb(query, con)
m = Map(layer)
mOg voilΓ β du fΓ₯r opp et kart som viser hvor det var mest aktivitet i luftrommet denne dagen. De varme, rΓΈde omrΓ₯dene indikerer hΓΈy konsentrasjon av datapunkter, mens kjΓΈligere omrΓ₯der har mindre trafikk.
Figur 11: Heatmap av flytrafikk 8. mars 2025, generert med Lonboard.
Politihelikopternes bevegelserΒΆ
Det kan vΓ¦re nyttig Γ₯ se all flytrafikk pΓ₯ ett kart β men det er enda mer spennende nΓ₯r vi snevrer det inn. La oss undersΓΈke politihelikopternes bevegelser 8. mars 2025.
- Finn alle observasjoner av politihelikoptre:
# Observasjoner av politihelikoptre 8. mars 2025sql = """
SELECT trace.timestamp as Time, ST_POINT(trace.lon, trace.lat) as geom, r as Reg from flights_08_03_2025
WHERE (r = 'LN-ORA' OR r = 'LN-ORB' or r = 'LN-ORC') GROUP BY ALL;
"""
query = con.sql(sql)from lonboard import Map, HeatmapLayer, PathLayer
layer = HeatmapLayer.from_duckdb(query, con)
m = Map(layer)
m
Figur 12: Heatmap av politihelikoptre 8. mars 2025, generert med Lonboard.
Se der, ja! Vi ser tydelig en konsentrasjon av aktivitet i Oslo-omrΓ₯det. Men hvilket helikopter var i lufta β og nΓ₯r?
- Oversikt over aktivitet per time:
# Se hvilket politihelikopter som var i luften nΓ₯rsql = """
SELECT r,
EXTRACT(HOUR FROM CAST(trace.timestamp as timestamp)) AS hour_of_day,
COUNT(*) AS num_points
FROM flights_08_03_2025 WHERE (r = 'LN-ORA' OR r = 'LN-ORB' or r = 'LN-ORC')
GROUP BY r, hour_of_day
ORDER BY hour_of_day;
"""
query = con.sql(sql)
query.pl()| r | hour_of_day | num_points |
|---|---|---|
| βLN-ORCβ | 7 | 555 |
| βLN-ORCβ | 12 | 417 |
| βLN-ORAβ | 14 | 1969 |
| βLN-ORAβ | 15 | 1316 |
| βLN-ORAβ | 19 | 502 |
| βLN-ORAβ | 20 | 3520 |
| βLN-ORAβ | 21 | 536 |
Her ser vi at LN-ORA og LN-ORC var aktive i lΓΈpet av dagen, mens LN-ORB enten var pΓ₯ bakken, utenfor dekning β eller ikke hadde transponderen aktivert.
- Visualiser bevegelsene til LN-ORA
# LN-ORA 8. mars 2025sql = """
SELECT r,
EXTRACT(HOUR FROM CAST(trace.timestamp as timestamp)) AS hour_of_day,
COUNT(*) AS num_points, ST_POINT(trace.lon, trace.lat) as geom, trace.timestamp
FROM flights_08_03_2025 WHERE r = 'LN-ORA'
GROUP BY ALL
ORDER BY hour_of_day;
"""
query = con.sql(sql)
query.pl()from lonboard import viz
viz(query, con=con)
Figur 13: Bevegelser for politihelikopteret LN-ORA, visualisert med Lonboard.
NΓ₯ ser vi alle registrerte bevegelser for LN-ORA denne dagen. Hovrer du med musepekeren over kartet, fΓ₯r du opp tidspunkter β og du kunne lett lagt til hΓΈyde, fart og andre datapunkter om ΓΈnskelig.
Visualisere et geografisk omrΓ₯deΒΆ
Tidligere i kurset har vi sett hvordan vi kan filtrere flydata basert pΓ₯ geografiske omrΓ₯der. NΓ₯ henter vi frem igjen H3-systemet, og bruker den til Γ₯ lage en visualisering av flytrafikken i en gitt sektor.
Ved Γ₯ velge en H3-sektor med opplΓΈsning 2 midt i SΓΈr-Norge, kan vi hente ut all flytrafikk i dette omrΓ₯det 8. mars 2025.
# Visualisere et geografisk omrΓ₯desql = """
SELECT r,
EXTRACT(HOUR FROM CAST(trace.timestamp as timestamp)) AS hour_of_day,
COUNT(*) AS num_points, ST_POINT(trace.lon, trace.lat) as geom, trace.timestamp
FROM flights_08_03_2025 WHERE h3_cell_to_parent(trace.h3_15, 2) = '82098ffffffffff'
GROUP BY ALL
ORDER BY hour_of_day;
"""
query = con.sql(sql)
query.pl()Etter en kjapp runde med Polars fΓ₯r vi en oversikt over aktivitet i den valgte sektoren.
| r | hour_of_day | num_points | binary (truncated) | timestamp |
|---|---|---|---|---|
| βB-304Kβ | 4 | 1 | b"\x00\x00...\x82o:N@" | β2025-03-08 04:17:45.440000β |
| βB-304Kβ | 4 | 1 | b"\x00\x00...\x95}W:N@" | β2025-03-08 04:17:46.250000β |
| βB-304Kβ | 4 | 1 | b"\x00\x00...\xee\xadH:N@" | β2025-03-08 04:17:46.800000β |
| βB-304Kβ | 4 | 1 | b"\x00\x00...\xe2\x03;:N@" | β2025-03-08 04:17:47.400000β |
| βB-304Kβ | 4 | 1 | b"\x00\x00...\xe6\x01,:N@" | β2025-03-08 04:17:48.110000β |
| β¦ | β¦ | β¦ | β¦ | β¦ |
| βLN-DYTβ | 23 | 1 | b"\x00\x00...\xc4\xcc$O@" | β2025-03-08 23:19:17.280000β |
| βLN-DYTβ | 23 | 1 | b"\x00\x00...\xb3!\xff$O@" | β2025-03-08 23:19:18.210000β |
| βLN-DYTβ | 23 | 1 | b"\x00\x00...\xd3\x82\x17%O@" | β2025-03-08 23:19:18.710000β |
| βLN-DYTβ | 23 | 1 | b"\x00\x00...\xe0(y%O@" | β2025-03-08 23:19:20.830000β |
| βLN-DYTβ | 23 | 1 | b"\x00\x00...\xbfD\xbc%O@" | β2025-03-08 23:19:22.290000β |
Heatmap over all trafikk i en gitt sektorΒΆ
Vi fortsetter med Γ₯ lage en Lonboard-heatmap av sektoren vΓ₯r:
# Lage heatmap av geografisk omrΓ₯delayer = HeatmapLayer.from_duckdb(query, con)
m = Map(layer)
m
Figur 14: Heatmap av flyaktivitet i en H3-sektor.
Interessant! Vi kan nesten ane heksagonens konturer. Men vi gjΓΈr det enda tydeligere:
Viz-kart over all trafikk i en gitt sektorΒΆ
# Lage Viz-kart av geografisk omrΓ₯deviz(query, con=con)
Figur 15: Viz-kart over geografisk omrΓ₯de.
Enkle linjer β og nΓ₯ ser vi tydelig H3-heksagonens form. Og som alltid med Viz-kart: du kan hovre med musepekeren for Γ₯ se detaljer som fly-ID og tidspunkter.
Visualisere all militær trafikk¢
NΓ₯ gjΓΈr vi en liten justering β og bruker samme metode for Γ₯ vise all militΓ¦rtrafikk i datasettet. Alt vi trenger er et filter pΓ₯ dbFlags = 8.
# Visualisere all militær trafikksql = """
SELECT r,
EXTRACT(HOUR FROM CAST(trace.timestamp as timestamp)) AS hour_of_day,
COUNT(*) AS num_points, ST_POINT(trace.lon, trace.lat) as geom, trace.timestamp
FROM flights_08_03_2025 WHERE dbFlags = 8
GROUP BY ALL
ORDER BY hour_of_day;
"""
query = con.sql(sql)
query.pl()| r | hour_of_day | num_points | geom (truncated) | timestamp |
|---|---|---|---|---|
| βN609GBβ | 3 | 1 | b"\x00\x00...\xff\xe8\xcdH@" | β2025-03-08 03:45:40.800000β |
| βN609GBβ | 3 | 1 | b"\x00\x00...\x30 | D\xceH@" |
| βN609GBβ | 3 | 1 | b"\x00\x00...\xec-\xe5\xd0H@" | β2025-03-08 03:45:58.170000β |
| βN609GBβ | 3 | 1 | b"\x00\x00...\xd5\x01\x10\xd1H@" | β2025-03-08 03:45:59.260000β |
| βN609GBβ | 3 | 1 | b"\x00\x00...\xa0g\xb3\xd2H@" | β2025-03-08 03:46:09.070000β |
| β¦ | β¦ | β¦ | β¦ | β¦ |
| βVQ-BXGβ | 19 | 1 | b"\x00\x00...\xb2\xb8\xff\x02J@" | β2025-03-08 19:09:23.110000β |
| βVQ-BXGβ | 19 | 1 | b"\x00\x00...\x81\x02\xef\x02J@" | β2025-03-08 19:09:24.800000β |
| βVQ-BXGβ | 19 | 1 | b"\x00\x00...\xc3*\xde\x02J@" | β2025-03-08 19:09:26.830000β |
| βVQ-BXGβ | 19 | 1 | b"\x00\x00...\x3c\xc1\x02J@" | β2025-03-08 19:09:30.110000β |
| βVQ-BXGβ | 19 | 1 | b"\x00\x00...\xeb\xfbp\x02J@" | β2025-03-08 19:09:39.060000β |
Og jammen dukker det ikke opp en rekke kjente (og mindre kjente) militærfartøy!
Lage heatmap av all militær trafikk¢
# Lage heatmap av all militær trafikklayer = HeatmapLayer.from_duckdb(query, con)
m = Map(layer)
m
Figur 16: Heatmap av all militær trafikk 8. mars 2025.
Her var det litt Γ₯ boltre seg i. La oss visualisere de samme dataene pΓ₯ et Viz-kart:
Viz-kart med detaljert infoΒΆ
# Lage Viz-kart av all militær trafikkfrom lonboard import viz
viz(query, con=con)
Figur 17: Viz-kart over militær trafikk.
Her fΓ₯r vi den fulle oversikten β og du kan enkelt undersΓΈke hvilke fartΓΈy som var i lufta, hvor og nΓ₯r.
OppgaverΒΆ
NΓ₯ har du fΓ₯tt en grunnleggende innfΓΈring i bruk av notebooks, DuckDB, Polars, Plotly og Lonboard. Tid for litt praktisk trening: